Как подключить Rust Web App к аналитике приложений?

Я использую следующие ящики: tracing, opentelemetry, tracing-opentelemetry, opentelemetry-application-insights, но консоль теперь заполнена сообщениями DEBUG/TRACE (связанными с соединением с информацией о приложении). У меня 3 вопроса:

  • Как правильно подключиться к аналитике приложений в Rust?
  • Как предоставить образцы телеметрии? Теперь пишет: «Не поддерживается этой версией агента/SDK».
  • Как скрыть журналы DEBUG/TRACE от статистики консоли и приложений?

Вот мой основной:

async fn init_tracing() {
    let app_insights_connection_string = "...";

    let client = reqwest::Client::new();

    let tracer = opentelemetry_application_insights::new_pipeline_from_connection_string(
        app_insights_connection_string,
    )
    .expect("valid connection string")
    .with_client(client)
    .with_live_metrics(true)
    .with_service_name("Rust Web App")
    .with_sample_rate(0.3)
    .install_batch(opentelemetry_sdk::runtime::Tokio);

    let telemetry = OpenTelemetryLayer::new(tracer);

    let subscriber = tracing_subscriber::registry()
        .with(tracing_subscriber::fmt::layer())
        .with(telemetry);

    subscriber.init();
}

#[tokio::main]
async fn main() {
    init_tracing().await;

    ...

    let app = Router::new()
        .merge(open_api_router())
        .nest_service("/api", api_router(app_state))
        .layer(CompressionLayer::new())
        .layer(TraceLayer::new_for_http());

   ...
   
   opentelemetry::global::shutdown_tracer_provider();
}

Вот мой Cargo.toml:

...
# HTTP Client
reqwest = { version = "0.11.27", features = ["default", "json", "blocking", "rustls-tls"] }

# Tracing
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["default", "env-filter", "serde", "chrono", "tracing", "serde_json"] }
tracing-opentelemetry = { version = "0.23.0", features = ["metrics", "async-trait", "thiserror"] }
opentelemetry = "0.22.0"
opentelemetry_sdk = { version = "0.22.1", features = ["default", "tokio", "serde", "serde_json", "opentelemetry-http", "rt-tokio", "metrics", "http", "trace"] }
opentelemetry-http = { version = "0.11.1", features = ["tokio", "reqwest"] }
opentelemetry-application-insights = { version = "0.30.0", features = ["reqwest", "reqwest-client", "reqwest-blocking-client", "metrics", "live-metrics", "reqwest-client-rustls", "reqwest-blocking-client-rustls", "reqwest-client-vendored-tls"] }
...

Вот часть вывода консоли запуска:

2024-04-27T18:43:08.789483Z DEBUG establish{db.system = "postgresql" otel.kind = "client"}: diesel_tracing::pg: establishing postgresql connection
2024-04-27T18:43:08.809463Z DEBUG establish{db.system = "postgresql" otel.kind = "client"}: diesel_tracing::pg: querying postgresql connection information
2024-04-27T18:43:08.810534Z  INFO uni_hub_api: ✅  Connection to the data is successful!
2024-04-27T18:43:08.810704Z DEBUG establish{db.system = "postgresql" otel.kind = "client"}: diesel_tracing::pg: establishing postgresql connection
2024-04-27T18:43:08.811979Z  INFO uni_hub_api: ⬆️ Migrations were applied successfully!
2024-04-27T18:43:08.813812Z  INFO uni_hub_api: 🚀 Server started successfully! Listening on 0.0.0.0:8080...
2024-04-27T18:43:08.830483Z DEBUG establish{db.system = "postgresql" otel.kind = "client"}: diesel_tracing::pg: querying postgresql connection information
2024-04-27T18:43:13.803307Z TRACE hyper::client::pool: checkout waiting for idle connection: ("https", switzerlandnorth.livediagnostics.monitor.azure.com)
2024-04-27T18:43:13.803684Z TRACE hyper::client::pool: checkout waiting for idle connection: ("https", switzerlandnorth-0.in.applicationinsights.azure.com)                     
2024-04-27T18:43:13.804410Z DEBUG reqwest::connect: starting new connection: https://switzerlandnorth-0.in.applicationinsights.azure.com/                                       
2024-04-27T18:43:13.804409Z DEBUG reqwest::connect: starting new connection: https://switzerlandnorth.livediagnostics.monitor.azure.com/                                        
2024-04-27T18:43:13.805209Z TRACE hyper::client::connect::http: Http::connect; scheme=Some("https"), host=Some("switzerlandnorth.livediagnostics.monitor.azure.com"), port=None 
2024-04-27T18:43:13.805223Z TRACE hyper::client::connect::http: Http::connect; scheme=Some("https"), host=Some("switzerlandnorth-0.in.applicationinsights.azure.com"), port=None
2024-04-27T18:43:13.805851Z DEBUG hyper::client::connect::dns: resolving host = "switzerlandnorth-0.in.applicationinsights.azure.com"                                             
2024-04-27T18:43:13.805880Z DEBUG hyper::client::connect::dns: resolving host = "switzerlandnorth.livediagnostics.monitor.azure.com"                                              
2024-04-27T18:43:14.067899Z DEBUG hyper::client::connect::http: connecting to 51.107.52.200:443
2024-04-27T18:43:14.099041Z DEBUG hyper::client::connect::http: connected to 51.107.52.200:443
2024-04-27T18:43:14.149468Z DEBUG hyper::client::connect::http: connecting to 51.107.48.68:443
2024-04-27T18:43:14.175926Z TRACE hyper::client::conn: client handshake Http1
2024-04-27T18:43:14.176562Z TRACE hyper::client::client: handshake complete, spawning background dispatcher task
2024-04-27T18:43:14.178442Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: Init, keep_alive: Busy }
2024-04-27T18:43:14.178763Z TRACE hyper::client::pool: checkout dropped for ("https", switzerlandnorth.livediagnostics.monitor.azure.com)
2024-04-27T18:43:14.179401Z TRACE encode_headers: hyper::proto::h1::role: Client::encode method=POST, body=Some(Known(184))
2024-04-27T18:43:14.180248Z TRACE hyper::proto::h1::encode: sized write, len = 184
2024-04-27T18:43:14.180483Z TRACE hyper::proto::h1::io: buffer.flatten self.len=489 buf.len=184
2024-04-27T18:43:14.180743Z DEBUG hyper::proto::h1::io: flushed 673 bytes
2024-04-27T18:43:14.180937Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: KeepAlive, keep_alive: Busy }
2024-04-27T18:43:14.181274Z DEBUG hyper::client::connect::http: connected to 51.107.48.68:443
2024-04-27T18:43:14.210945Z TRACE hyper::proto::h1::conn: Conn::read_head
2024-04-27T18:43:14.211246Z TRACE hyper::proto::h1::io: received 367 bytes
2024-04-27T18:43:14.211496Z TRACE parse_headers: hyper::proto::h1::role: Response.parse bytes=367
2024-04-27T18:43:14.212061Z TRACE parse_headers: hyper::proto::h1::role: Response.parse Complete(367)
2024-04-27T18:43:14.212935Z DEBUG hyper::proto::h1::io: parsed 9 headers
2024-04-27T18:43:14.213157Z DEBUG hyper::proto::h1::conn: incoming body is empty
2024-04-27T18:43:14.213403Z TRACE hyper::proto::h1::conn: maybe_notify; read_from_io blocked
2024-04-27T18:43:14.213651Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: Init, keep_alive: Idle }
2024-04-27T18:43:14.213864Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: Init, keep_alive: Idle }
2024-04-27T18:43:14.214743Z TRACE hyper::client::pool: put; add idle connection for ("https", switzerlandnorth.livediagnostics.monitor.azure.com)
2024-04-27T18:43:14.214995Z DEBUG hyper::client::pool: pooling idle connection for ("https", switzerlandnorth.livediagnostics.monitor.azure.com)
2024-04-27T18:43:14.215486Z TRACE hyper::client::pool: idle interval checking for expired
2024-04-27T18:43:14.249996Z TRACE hyper::client::conn: client handshake Http1
2024-04-27T18:43:14.250311Z TRACE hyper::client::client: handshake complete, spawning background dispatcher task
2024-04-27T18:43:14.250622Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: Init, keep_alive: Busy }
2024-04-27T18:43:14.250926Z TRACE hyper::client::pool: checkout dropped for ("https", switzerlandnorth-0.in.applicationinsights.azure.com)
2024-04-27T18:43:14.251396Z TRACE encode_headers: hyper::proto::h1::role: Client::encode method=POST, body=Some(Known(1057))
2024-04-27T18:43:14.251705Z TRACE hyper::proto::h1::encode: sized write, len = 1057
2024-04-27T18:43:14.251865Z TRACE hyper::proto::h1::io: buffer.flatten self.len=177 buf.len=1057
2024-04-27T18:43:14.252136Z DEBUG hyper::proto::h1::io: flushed 1234 bytes
2024-04-27T18:43:14.252312Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: KeepAlive, keep_alive: Busy }
2024-04-27T18:43:14.284064Z TRACE hyper::proto::h1::conn: Conn::read_head
2024-04-27T18:43:14.284317Z TRACE hyper::proto::h1::io: received 308 bytes
2024-04-27T18:43:14.284499Z TRACE parse_headers: hyper::proto::h1::role: Response.parse bytes=308
2024-04-27T18:43:14.285003Z TRACE parse_headers: hyper::proto::h1::role: Response.parse Complete(240)
2024-04-27T18:43:14.285279Z DEBUG hyper::proto::h1::io: parsed 6 headers
2024-04-27T18:43:14.285482Z DEBUG hyper::proto::h1::conn: incoming body is chunked encoding
2024-04-27T18:43:14.285658Z TRACE hyper::proto::h1::decode: decode; state=Chunked { state: Start, chunk_len: 0, extensions_cnt: 0 }
2024-04-27T18:43:14.285859Z TRACE hyper::proto::h1::decode: Read chunk start
2024-04-27T18:43:14.285993Z TRACE hyper::proto::h1::decode: Read chunk hex size
2024-04-27T18:43:14.286149Z TRACE hyper::proto::h1::decode: Read chunk hex size
2024-04-27T18:43:14.286268Z TRACE hyper::proto::h1::decode: Chunk size is 62
2024-04-27T18:43:14.286421Z DEBUG hyper::proto::h1::decode: incoming chunked header: 0x3E (62 bytes)
2024-04-27T18:43:14.286577Z TRACE hyper::proto::h1::decode: Chunked read, remaining=62
2024-04-27T18:43:14.286718Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Body(Chunked { state: BodyCr, chunk_len: 0, extensions_cnt: 0 }), writing: KeepAlive, keep_alive: Busy }
2024-04-27T18:43:14.286991Z TRACE hyper::proto::h1::decode: decode; state=Chunked { state: BodyCr, chunk_len: 0, extensions_cnt: 0 }
2024-04-27T18:43:14.287150Z TRACE hyper::proto::h1::decode: Read chunk hex size
2024-04-27T18:43:14.287278Z TRACE hyper::proto::h1::io: received 5 bytes
2024-04-27T18:43:14.287395Z TRACE hyper::proto::h1::decode: Read chunk hex size
2024-04-27T18:43:14.287509Z TRACE hyper::proto::h1::decode: Chunk size is 0
2024-04-27T18:43:14.287624Z TRACE hyper::proto::h1::decode: end of chunked
2024-04-27T18:43:14.287744Z DEBUG hyper::proto::h1::conn: incoming body completed
2024-04-27T18:43:14.287923Z TRACE hyper::proto::h1::conn: maybe_notify; read_from_io blocked
2024-04-27T18:43:14.288070Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: Init, keep_alive: Idle }
2024-04-27T18:43:14.288223Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: Init, keep_alive: Idle }
2024-04-27T18:43:14.288366Z TRACE hyper::client::pool: put; add idle connection for ("https", switzerlandnorth-0.in.applicationinsights.azure.com)
2024-04-27T18:43:14.288507Z DEBUG hyper::client::pool: pooling idle connection for ("https", switzerlandnorth-0.in.applicationinsights.azure.com)
2024-04-27T18:43:14.288715Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: Init, keep_alive: Idle }
2024-04-27T18:43:18.797873Z TRACE hyper::client::pool: take? ("https", switzerlandnorth-0.in.applicationinsights.azure.com): expiration = Some(90s)
2024-04-27T18:43:18.798350Z DEBUG hyper::client::pool: reuse idle connection for ("https", switzerlandnorth-0.in.applicationinsights.azure.com)
2024-04-27T18:43:18.798871Z TRACE encode_headers: hyper::proto::h1::role: Client::encode method=POST, body=Some(Known(933))
2024-04-27T18:43:18.799331Z TRACE hyper::proto::h1::encode: sized write, len = 933
2024-04-27T18:43:18.799635Z TRACE hyper::proto::h1::io: buffer.flatten self.len=176 buf.len=933
2024-04-27T18:43:18.800016Z DEBUG hyper::proto::h1::io: flushed 1109 bytes
2024-04-27T18:43:18.800317Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: KeepAlive, keep_alive: Busy }
2024-04-27T18:43:18.833117Z TRACE hyper::proto::h1::conn: Conn::read_head
2024-04-27T18:43:18.833488Z TRACE hyper::proto::h1::io: received 310 bytes
2024-04-27T18:43:18.833801Z TRACE parse_headers: hyper::proto::h1::role: Response.parse bytes=310
2024-04-27T18:43:18.834195Z TRACE parse_headers: hyper::proto::h1::role: Response.parse Complete(240)
2024-04-27T18:43:18.834651Z DEBUG hyper::proto::h1::io: parsed 6 headers
2024-04-27T18:43:18.834946Z DEBUG hyper::proto::h1::conn: incoming body is chunked encoding
2024-04-27T18:43:18.835206Z TRACE hyper::proto::h1::decode: decode; state=Chunked { state: Start, chunk_len: 0, extensions_cnt: 0 }
2024-04-27T18:43:18.835485Z TRACE hyper::proto::h1::decode: Read chunk start
2024-04-27T18:43:18.835777Z TRACE hyper::proto::h1::decode: Read chunk hex size
2024-04-27T18:43:18.835959Z TRACE hyper::proto::h1::decode: Read chunk hex size
2024-04-27T18:43:18.836138Z TRACE hyper::proto::h1::decode: Chunk size is 64
2024-04-27T18:43:18.836293Z DEBUG hyper::proto::h1::decode: incoming chunked header: 0x40 (64 bytes)
2024-04-27T18:43:18.836485Z TRACE hyper::proto::h1::decode: Chunked read, remaining=64
2024-04-27T18:43:18.836663Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Body(Chunked { state: BodyCr, chunk_len: 0, extensions_cnt: 0 }), writing: KeepAlive, keep_alive: Busy }
2024-04-27T18:43:18.836995Z TRACE hyper::proto::h1::decode: decode; state=Chunked { state: BodyCr, chunk_len: 0, extensions_cnt: 0 }
2024-04-27T18:43:18.837136Z TRACE hyper::proto::h1::decode: Read chunk hex size
2024-04-27T18:43:18.837296Z TRACE hyper::proto::h1::io: received 5 bytes
2024-04-27T18:43:18.837449Z TRACE hyper::proto::h1::decode: Read chunk hex size
2024-04-27T18:43:18.837581Z TRACE hyper::proto::h1::decode: Chunk size is 0
2024-04-27T18:43:18.837716Z TRACE hyper::proto::h1::decode: end of chunked
2024-04-27T18:43:18.837835Z DEBUG hyper::proto::h1::conn: incoming body completed
2024-04-27T18:43:18.837975Z TRACE hyper::proto::h1::conn: maybe_notify; read_from_io blocked
2024-04-27T18:43:18.838124Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: Init, keep_alive: Idle }
2024-04-27T18:43:18.838256Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: Init, keep_alive: Idle }
2024-04-27T18:43:18.838408Z TRACE hyper::client::pool: put; add idle connection for ("https", switzerlandnorth-0.in.applicationinsights.azure.com)
2024-04-27T18:43:18.838571Z DEBUG hyper::client::pool: pooling idle connection for ("https", switzerlandnorth-0.in.applicationinsights.azure.com)
2024-04-27T18:43:18.838788Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: Init, keep_alive: Idle }
2024-04-27T18:43:19.224346Z TRACE hyper::client::pool: take? ("https", switzerlandnorth.livediagnostics.monitor.azure.com): expiration = Some(90s)
2024-04-27T18:43:19.224570Z DEBUG hyper::client::pool: reuse idle connection for ("https", switzerlandnorth.livediagnostics.monitor.azure.com)
2024-04-27T18:43:19.224982Z TRACE encode_headers: hyper::proto::h1::role: Client::encode method=POST, body=Some(Known(184))
2024-04-27T18:43:19.225308Z TRACE hyper::proto::h1::encode: sized write, len = 184
2024-04-27T18:43:19.225582Z TRACE hyper::proto::h1::io: buffer.flatten self.len=489 buf.len=184
2024-04-27T18:43:19.225936Z DEBUG hyper::proto::h1::io: flushed 673 bytes
2024-04-27T18:43:19.226238Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: KeepAlive, keep_alive: Busy }
2024-04-27T18:43:19.256445Z TRACE hyper::proto::h1::conn: Conn::read_head
2024-04-27T18:43:19.256798Z TRACE hyper::proto::h1::io: received 367 bytes
2024-04-27T18:43:19.257123Z TRACE parse_headers: hyper::proto::h1::role: Response.parse bytes=367
2024-04-27T18:43:19.257475Z TRACE parse_headers: hyper::proto::h1::role: Response.parse Complete(367)
2024-04-27T18:43:19.258103Z DEBUG hyper::proto::h1::io: parsed 9 headers
2024-04-27T18:43:19.258393Z DEBUG hyper::proto::h1::conn: incoming body is empty
2024-04-27T18:43:19.258633Z TRACE hyper::proto::h1::conn: maybe_notify; read_from_io blocked
2024-04-27T18:43:19.258974Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: Init, keep_alive: Idle }
2024-04-27T18:43:19.259218Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: Init, keep_alive: Idle }
2024-04-27T18:43:19.259470Z TRACE hyper::client::pool: put; add idle connection for ("https", switzerlandnorth.livediagnostics.monitor.azure.com)
2024-04-27T18:43:19.259642Z DEBUG hyper::client::pool: pooling idle connection for ("https", switzerlandnorth.livediagnostics.monitor.azure.com)

В Application Insights в Live Metrics метрики отображаются правильно, но образец телеметрии отсутствует. Там просто написано Not supported by this Agent/SDK version.

Журналы DEBUG/TRACE также отправляются в службу аналитики приложений и затем доступны в разделе Журналы -> запрос трассировки.

Я был бы очень признателен, если бы кто-нибудь мог мне в этом помочь. Я новичок в Rust и последние два дня потратил на изучение этого вопроса.

До сих пор я пытался добавить .with_max_level к слоям трассировки, но получаю следующую ошибку:

the method `with_max_level` exists for struct `OpenTelemetryLayer<_, Tracer>`, but its trait bounds were not satisfied [E0599] method cannot be called on `OpenTelemetryLayer<_, Tracer>` due to unsatisfied trait bounds Note: the following trait bounds were not satisfied: `OpenTelemetryLayer<_, opentelemetry_sdk::trace::Tracer>: MakeWriter<'_>` which is required by `OpenTelemetryLayer<_, opentelemetry_sdk::trace::Tracer>: MakeWriterExt<'_>` `&OpenTelemetryLayer<_, opentelemetry_sdk::trace::Tracer>: MakeWriter<'_>` which is required by `&OpenTelemetryLayer<_, opentelemetry_sdk::trace::Tracer>: MakeWriterExt<'_>` `&mut OpenTelemetryLayer<_, opentelemetry_sdk::trace::Tracer>: MakeWriter<'_>` which is required by `&mut OpenTelemetryLayer<_, opentelemetry_sdk::trace::Tracer>: MakeWriterExt<'_>`

Чтобы установить максимальный уровень журнала для трассировки, вы обычно используете метод with_max_level в tracing_subscriber::registry() вместо OpenTelemetryLayer.

Suresh Chikkam 29.04.2024 13:05
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
2
102
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как скрыть журналы DEBUG/TRACE от статистики консоли и приложений?

  • Приведенный выше код выглядит хорошо. Для управления уровнем журнала вы можете настроить фильтр подписчика трассировки. Поскольку вы используете tracing-subscriber, вы можете использовать его функцию EnvFilter для установки уровня журнала. Проверьте следующие шаги, чтобы установить уровень журнала с помощью функции init_tracing.
use tracing_subscriber::EnvFilter;

async fn init_tracing() {
    let app_insights_connection_string = "...";

    let client = reqwest::Client::new();

    let tracer = opentelemetry_application_insights::new_pipeline_from_connection_string(
        app_insights_connection_string,
    )
    .expect("valid connection string")
    .with_client(client)
    .with_live_metrics(true)
    .with_service_name("Rust Web App")
    .with_sample_rate(0.3)
    .install_batch(opentelemetry_sdk::runtime::Tokio);

    let telemetry = OpenTelemetryLayer::new(tracer);

    let filter = EnvFilter::from_default_env()
        .add_directive(tracing_subscriber::filter::LevelFilter::INFO.into());

    let subscriber = tracing_subscriber::registry()
        .with(tracing_subscriber::fmt::layer())
        .with(telemetry)
        .with(filter);

    subscriber.init();
}

Приведенная выше настройка скроет журналы DEBUG и TRACE как с консоли, так и с Application Insights.

  • Используйте init_tracing() в точке входа вашего приложения. Вызовите функцию init_tracing() в начале приложения. Настройте параметры конфигурации, такие как имя службы и частота дискретизации, в соответствии с требованиями.

Логи консоли:

INFO uni_hub_api: ✅ Connection to the data is successful!
INFO uni_hub_api: ⬆️ Migrations were applied successfully!
INFO uni_hub_api: 🚀 Server started successfully! Listening on 0.0.0.0:8080...

Ссылка:

Другие вопросы по теме

Похожие вопросы

Как правильно писать в базу данных с многопоточностью?
Как инициализировать две переменные в операторе сопоставления, не вызывая раздражения средства проверки заимствований?
Невозможно собрать программу Solana NFT с помощью команды «anchor build» из-за проблемы с версией Rusc
Каков наиболее эффективный способ создания изменяемого фрагмента из изменяемых фрагментов в Rust?
ВСЕГДА ли использование `std::sync::Mutex` в точке `await` вызывает взаимоблокировку?
Перенос кода C с изменяемыми заимствованиями — ошибка во время выполнения (пример nappgui)
Что делает #[inline]?
Почему переменная в родительской области находится «вне области видимости» дочерней
Явное время жизни для себя в признаке, похоже, приводит к тому, что «E0499 не может заимствовать `*emitter` как изменяемый более одного раза» в цикле
Каков способ «наименования» списка кортежей в Rust с наименьшими затратами времени выполнения?