diff --git a/Cargo.lock b/Cargo.lock index dc876082..c9ef8465 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -566,9 +566,9 @@ dependencies = [ [[package]] name = "biscuit" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e28fc7c56c61743a01d0d1b73e4fed68b8a4f032ea3a2d4bb8c6520a33fc05a" +checksum = "2dbfddc8cc5cc927876d9f138e7ded44c6116c544d3cca2c3a2759e46ba916c7" dependencies = [ "chrono", "data-encoding", @@ -3130,7 +3130,6 @@ dependencies = [ "hyper", "hyper-util", "rustls 0.23.37", - "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls", @@ -4736,9 +4735,8 @@ dependencies = [ [[package]] name = "opentelemetry" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e87237e2775f74896f9ad219d26a2081751187eb7c9f5c58dde20a23b95d16c" +version = "0.31.0" +source = "git+https://github.com/stalwartlabs/opentelemetry-rust#f32f79ee7f0c7c5403f20d878fa05f3181fbfeb0" dependencies = [ "futures-core", "futures-sink", @@ -4750,72 +4748,64 @@ dependencies = [ [[package]] name = "opentelemetry-http" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46d7ab32b827b5b495bd90fa95a6cb65ccc293555dcc3199ae2937d2d237c8ed" +version = "0.31.0" +source = "git+https://github.com/stalwartlabs/opentelemetry-rust#f32f79ee7f0c7c5403f20d878fa05f3181fbfeb0" dependencies = [ "async-trait", "bytes", "http 1.4.0", "opentelemetry", - "reqwest 0.12.28", - "tracing", + "reqwest 0.13.2", ] [[package]] name = "opentelemetry-otlp" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d899720fe06916ccba71c01d04ecd77312734e2de3467fd30d9d580c8ce85656" +version = "0.31.0" +source = "git+https://github.com/stalwartlabs/opentelemetry-rust#f32f79ee7f0c7c5403f20d878fa05f3181fbfeb0" dependencies = [ - "futures-core", "http 1.4.0", "opentelemetry", "opentelemetry-http", "opentelemetry-proto", "opentelemetry_sdk", "prost", - "reqwest 0.12.28", + "reqwest 0.13.2", "thiserror 2.0.18", "tokio", "tonic", - "tracing", + "tonic-types", ] [[package]] name = "opentelemetry-proto" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c40da242381435e18570d5b9d50aca2a4f4f4d8e146231adb4e7768023309b3" +version = "0.31.0" +source = "git+https://github.com/stalwartlabs/opentelemetry-rust#f32f79ee7f0c7c5403f20d878fa05f3181fbfeb0" dependencies = [ "opentelemetry", "opentelemetry_sdk", "prost", "tonic", + "tonic-prost", ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b29a9f89f1a954936d5aa92f19b2feec3c8f3971d3e96206640db7f9706ae3" +version = "0.31.0" +source = "git+https://github.com/stalwartlabs/opentelemetry-rust#f32f79ee7f0c7c5403f20d878fa05f3181fbfeb0" [[package]] name = "opentelemetry_sdk" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afdefb21d1d47394abc1ba6c57363ab141be19e27cc70d0e422b7f303e4d290b" +version = "0.31.0" +source = "git+https://github.com/stalwartlabs/opentelemetry-rust#f32f79ee7f0c7c5403f20d878fa05f3181fbfeb0" dependencies = [ "futures-channel", "futures-executor", "futures-util", - "glob", "opentelemetry", "percent-encoding", + "portable-atomic", "rand 0.9.2", - "serde_json", "thiserror 2.0.18", - "tracing", ] [[package]] @@ -5383,9 +5373,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.5" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" dependencies = [ "bytes", "prost-derive", @@ -5393,17 +5383,26 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.13.5" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.117", ] +[[package]] +name = "prost-types" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" +dependencies = [ + "prost", +] + [[package]] name = "proxy-header" version = "0.1.2" @@ -6015,7 +6014,6 @@ checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", "bytes", - "futures-channel", "futures-core", "futures-util", "http 1.4.0", @@ -6030,7 +6028,6 @@ dependencies = [ "pin-project-lite", "quinn", "rustls 0.23.37", - "rustls-native-certs", "rustls-pki-types", "serde", "serde_json", @@ -6039,7 +6036,7 @@ dependencies = [ "tokio", "tokio-rustls", "tokio-util", - "tower 0.5.3", + "tower", "tower-http", "tower-service", "url", @@ -6082,7 +6079,7 @@ dependencies = [ "tokio", "tokio-rustls", "tokio-util", - "tower 0.5.3", + "tower", "tower-http", "tower-service", "url", @@ -7906,9 +7903,9 @@ dependencies = [ [[package]] name = "tonic" -version = "0.12.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec" dependencies = [ "async-trait", "base64 0.22.1", @@ -7921,18 +7918,39 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "prost", "rustls-native-certs", - "rustls-pemfile", + "sync_wrapper", "tokio", "tokio-rustls", "tokio-stream", - "tower 0.4.13", + "tower", "tower-layer", "tower-service", "tracing", ] +[[package]] +name = "tonic-prost" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55376a0bbaa4975a3f10d009ad763d8f4108f067c7c2e74f3001fb49778d309" +dependencies = [ + "bytes", + "prost", + "tonic", +] + +[[package]] +name = "tonic-types" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a875a902255423d34c1f20838ab374126db8eb41625b7947a1d54113b0b7399" +dependencies = [ + "prost", + "prost-types", + "tonic", +] + [[package]] name = "totp-rs" version = "5.7.1" @@ -7948,26 +7966,6 @@ dependencies = [ "urlencoding", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand 0.8.5", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tower" version = "0.5.3" @@ -7976,11 +7974,15 @@ checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", + "indexmap 2.13.1", "pin-project-lite", + "slab", "sync_wrapper", "tokio", + "tokio-util", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -8001,7 +8003,7 @@ dependencies = [ "pin-project-lite", "tokio", "tokio-util", - "tower 0.5.3", + "tower", "tower-layer", "tower-service", ] diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 03abb52a..376e12e8 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -43,10 +43,10 @@ x509-parser = "0.18" pem = "3.0" chrono = { version = "0.4", features = ["serde"] } hyper = { version = "1.0.1", features = ["server", "http1", "http2"] } -opentelemetry = { version = "0.29" } -opentelemetry_sdk = { version = "0.29" } -opentelemetry-otlp = { version = "0.29", default-features = false, features = ["reqwest-client", "http-proto", "trace", "metrics", "logs", "internal-logs", "grpc-tonic", "tls-roots", "reqwest-rustls"] } -opentelemetry-semantic-conventions = { version = "0.29.0" } +opentelemetry = { git = "https://github.com/stalwartlabs/opentelemetry-rust" } +opentelemetry_sdk = { git = "https://github.com/stalwartlabs/opentelemetry-rust" } +opentelemetry-otlp = { git = "https://github.com/stalwartlabs/opentelemetry-rust", default-features = false, features = ["reqwest-client", "http-proto", "trace", "metrics", "logs", "internal-logs", "grpc-tonic", "tls-aws-lc", "tls-roots", "reqwest-rustls"] } +opentelemetry-semantic-conventions = { git = "https://github.com/stalwartlabs/opentelemetry-rust" } prometheus = { version = "0.14", default-features = false } imagesize = "0.14" sha1 = "0.11" @@ -64,7 +64,7 @@ pwhash = "1.0.0" xxhash-rust = { version = "0.8.5", features = ["xxh3"] } psl = "2" aes-gcm-siv = "0.11.1" -biscuit = "0.7.0" +biscuit = "0.8.0" rsa = "0.9.2" p256 = { version = "0.13", features = ["ecdh"] } p384 = { version = "0.13", features = ["ecdh"] } diff --git a/crates/common/src/config/telemetry.rs b/crates/common/src/config/telemetry.rs index 2d5a35a0..53808015 100644 --- a/crates/common/src/config/telemetry.rs +++ b/crates/common/src/config/telemetry.rs @@ -8,15 +8,11 @@ use crate::config::storage::Storage; use ahash::{AHashMap, AHashSet}; use base64::{Engine, engine::general_purpose::STANDARD}; use hyper::HeaderMap; -use opentelemetry::{InstrumentationScope, KeyValue, logs::LoggerProvider}; +use opentelemetry::{InstrumentationScope, KeyValue}; use opentelemetry_otlp::{ LogExporter, MetricExporter, SpanExporter, WithExportConfig, WithHttpConfig, }; -use opentelemetry_sdk::{ - Resource, - logs::{SdkLogger, SdkLoggerProvider}, - metrics::Temporality, -}; +use opentelemetry_sdk::{Resource, metrics::Temporality}; use opentelemetry_semantic_conventions::resource::SERVICE_VERSION; use registry::schema::{ enums::{EventPolicy, LogRotateFrequency}, @@ -57,7 +53,6 @@ pub struct OtelTracer { pub span_exporter: SpanExporter, pub span_exporter_enable: bool, pub log_exporter: LogExporter, - pub log_provider: SdkLogger, pub log_exporter_enable: bool, pub throttle: Duration, } @@ -307,9 +302,6 @@ impl Tracers { throttle: tracer.throttle.into_inner(), span_exporter_enable: tracer.enable_span_exporter, log_exporter_enable: tracer.enable_log_exporter, - log_provider: SdkLoggerProvider::builder() - .build() - .logger("stalwart"), }) } (Err(err), _) => { @@ -356,9 +348,6 @@ impl Tracers { throttle: tracer.throttle.into_inner(), span_exporter_enable: tracer.enable_span_exporter, log_exporter_enable: tracer.enable_log_exporter, - log_provider: SdkLoggerProvider::builder() - .build() - .logger("stalwart"), }) } (Err(err), _) => { diff --git a/crates/common/src/telemetry/metrics/otel.rs b/crates/common/src/telemetry/metrics/otel.rs index 80f42ab1..e7dd9efd 100644 --- a/crates/common/src/telemetry/metrics/otel.rs +++ b/crates/common/src/telemetry/metrics/otel.rs @@ -8,8 +8,8 @@ use crate::config::telemetry::OtelMetrics; use opentelemetry_sdk::metrics::{ Temporality, data::{ - Gauge, GaugeDataPoint, Histogram, HistogramDataPoint, Metric, ResourceMetrics, - ScopeMetrics, Sum, SumDataPoint, + AggregatedMetrics, Gauge, GaugeDataPoint, Histogram, HistogramDataPoint, Metric, + MetricData, ResourceMetrics, ScopeMetrics, Sum, SumDataPoint, }, exporter::PushMetricExporter, }; @@ -23,78 +23,64 @@ impl OtelMetrics { // Add counters for counter in Collector::collect_counters(is_enterprise) { - metrics.push(Metric { - name: counter.id().as_str().into(), - description: counter.id().description().into(), - unit: "events".into(), - data: Box::new(Sum { - data_points: vec![SumDataPoint { - attributes: vec![], - value: counter.value(), - exemplars: vec![], - }], - temporality: Temporality::Cumulative, - is_monotonic: true, + metrics.push(Metric::new( + counter.id().as_str(), + counter.id().description(), + "events", + AggregatedMetrics::U64(MetricData::Sum(Sum::new( + vec![SumDataPoint::new(vec![], counter.value(), vec![])], start_time, time, - }), - }); + Temporality::Cumulative, + true, + ))), + )); } // Add gauges for gauge in Collector::collect_gauges(is_enterprise) { - metrics.push(Metric { - name: gauge.id().as_str().into(), - description: gauge.id().description().into(), - unit: gauge.id().unit().into(), - data: Box::new(Gauge { - data_points: vec![GaugeDataPoint { - attributes: vec![], - value: gauge.get(), - exemplars: vec![], - }], - start_time: start_time.into(), + metrics.push(Metric::new( + gauge.id().as_str(), + gauge.id().description(), + gauge.id().unit(), + AggregatedMetrics::U64(MetricData::Gauge(Gauge::new( + vec![GaugeDataPoint::new(vec![], gauge.get(), vec![])], + Some(start_time), time, - }), - }); + ))), + )); } // Add histograms for histogram in Collector::collect_histograms(is_enterprise) { - metrics.push(Metric { - name: histogram.id().as_str().into(), - description: histogram.id().description().into(), - unit: histogram.id().unit().into(), - data: Box::new(Histogram { - data_points: vec![HistogramDataPoint { - attributes: vec![], - count: histogram.count(), - bounds: histogram.upper_bounds_vec(), - bucket_counts: histogram.buckets_vec(), - min: histogram.min(), - max: histogram.max(), - sum: histogram.sum(), - exemplars: vec![], - }], - temporality: Temporality::Cumulative, + metrics.push(Metric::new( + histogram.id().as_str(), + histogram.id().description(), + histogram.id().unit(), + AggregatedMetrics::U64(MetricData::Histogram(Histogram::new( + vec![HistogramDataPoint::new( + vec![], + histogram.count(), + histogram.upper_bounds_vec(), + histogram.buckets_vec(), + histogram.min(), + histogram.max(), + histogram.sum(), + vec![], + )], start_time, time, - }), - }); + Temporality::Cumulative, + ))), + )); } // Export metrics - if let Err(err) = self - .exporter - .export(&mut ResourceMetrics { - resource: self.resource.clone(), - scope_metrics: vec![ScopeMetrics { - scope: self.instrumentation.clone(), - metrics, - }], - }) - .await - { + let rm = ResourceMetrics::new( + self.resource.clone(), + vec![ScopeMetrics::new(self.instrumentation.clone(), metrics)], + ); + if let Err(err) = self.exporter.export(&rm).await { trc::event!( Telemetry(TelemetryEvent::OtelMetricsExporterError), Reason = err.to_string(), diff --git a/crates/common/src/telemetry/tracers/otel.rs b/crates/common/src/telemetry/tracers/otel.rs index 1d6747e2..22ded231 100644 --- a/crates/common/src/telemetry/tracers/otel.rs +++ b/crates/common/src/telemetry/tracers/otel.rs @@ -171,6 +171,7 @@ where ), dropped_attributes_count: 0, parent_span_id: 0.into(), + parent_span_is_remote: false, name: start_span.inner.typ.as_str().into(), start_time: UNIX_EPOCH + Duration::from_secs(start_span.inner.timestamp), end_time: UNIX_EPOCH + Duration::from_secs(end_span.inner.timestamp), @@ -186,9 +187,8 @@ where impl OtelTracer { fn build_log_record(&self, event: &Event) -> SdkLogRecord { use opentelemetry::logs::LogRecord; - use opentelemetry::logs::Logger; - let mut record = self.log_provider.create_log_record(); + let mut record = SdkLogRecord::new(); record.set_event_name(event.inner.typ.as_str()); record.set_severity_number(match event.inner.level { Level::Trace => Severity::Trace, diff --git a/crates/http/src/api/mod.rs b/crates/http/src/api/mod.rs index 0051be2d..0cd891ef 100644 --- a/crates/http/src/api/mod.rs +++ b/crates/http/src/api/mod.rs @@ -15,8 +15,7 @@ pub mod diagnose; use crate::{ api::diagnose::{DeliveryStage, spawn_delivery_diagnose}, auth::{ - authenticate::Authenticator, oauth::auth::OAuthApiHandler, - permissions::PermissionsApiHandler, + authenticate::Authenticator, oauth::auth::OAuthApiHandler, permissions::AccountApiHandler, }, }; use common::{ @@ -85,10 +84,10 @@ impl ManagementApi for Server { Err(trc::ResourceEvent::NotFound.into_err()) } } - "permissions" => { + "account" => { // Authenticate request let (_in_flight, access_token) = self.authenticate_headers(req, session).await?; - self.handle_permissions_request(&access_token).await + self.handle_account_request(&access_token).await } "token" => { let access_token = self.management_access_token(req, session).await?; diff --git a/crates/http/src/auth/permissions.rs b/crates/http/src/auth/permissions.rs index c68645e5..79f1e29d 100644 --- a/crates/http/src/auth/permissions.rs +++ b/crates/http/src/auth/permissions.rs @@ -6,24 +6,25 @@ use common::{Server, auth::AccessToken}; use http_proto::{HttpResponse, JsonResponse, ToHttpResponse}; -use registry::schema::enums::Permission; +use registry::schema::enums::{Locale, Permission}; use serde::Serialize; #[derive(Debug, Clone, Serialize)] -pub struct Permissions { +pub struct Account { pub permissions: Vec, pub edition: &'static str, + pub locale: Locale, } -pub trait PermissionsApiHandler: Sync + Send { - fn handle_permissions_request( +pub trait AccountApiHandler: Sync + Send { + fn handle_account_request( &self, access_token: &AccessToken, ) -> impl Future> + Send; } -impl PermissionsApiHandler for Server { - async fn handle_permissions_request( +impl AccountApiHandler for Server { + async fn handle_account_request( &self, access_token: &AccessToken, ) -> trc::Result { @@ -41,9 +42,12 @@ impl PermissionsApiHandler for Server { }; // SPDX-SnippetEnd - Ok(JsonResponse::new(Permissions { + let account_info = self.account_info(access_token.account_id()).await?; + + Ok(JsonResponse::new(Account { permissions: access_token.permissions(), edition, + locale: account_info.locale(), }) .into_http_response()) } diff --git a/tests/Cargo.toml b/tests/Cargo.toml index a21b89cb..5b75cbdd 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -50,7 +50,7 @@ mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] } mail-builder = "0.4.4" sieve-rs = { version = "0.7", features = ["rkyv"] } utils = { path = "../crates/utils", features = ["test_mode"] } -jmap-client = { path = "/Users/me/code/jmap-client", features = ["websockets", "debug", "async"] } +jmap-client = { path = "/Users/me/code/jmap-client", features = ["websockets", "ring", "debug", "async"] } tokio = { version = "1.47", features = ["full"] } tokio-rustls = { version = "0.26", default-features = false, features = ["aws_lc_rs", "tls12"] } rustls = { version = "0.23.5", default-features = false, features = ["std", "aws_lc_rs", "tls12"] } @@ -75,7 +75,7 @@ num_cpus = "1.15.0" async-trait = "0.1.68" chrono = "0.4" ring = { version = "0.17" } -biscuit = "0.7.0" +biscuit = "0.8.0" form_urlencoded = "1.1.0" rkyv = { version = "0.8.10", features = ["little_endian"] } compact_str = "0.9.0"