Skip to content

Commit 6d582af

Browse files
committed
attempting to write a new test to validate this new setting
1 parent 289145a commit 6d582af

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

tests/integ_tests/metrics_tests.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use anyhow::anyhow;
22
use assert_matches::assert_matches;
3+
use std::sync::Mutex;
34
use std::{collections::HashMap, env, net::SocketAddr, sync::Arc, time::Duration};
45
use temporal_client::{
56
WorkflowClientTrait, WorkflowOptions, WorkflowService, REQUEST_LATENCY_HISTOGRAM_NAME,
@@ -45,6 +46,7 @@ use temporal_sdk_core_test_utils::{
4546
get_integ_server_options, get_integ_telem_options, CoreWfStarter, NAMESPACE, OTEL_URL_ENV_VAR,
4647
};
4748
use tokio::{join, sync::Barrier, task::AbortHandle};
49+
use tracing_subscriber::fmt::MakeWriter;
4850
use url::Url;
4951

5052
static ANY_PORT: &str = "127.0.0.1:0";
@@ -815,3 +817,124 @@ async fn evict_on_complete_does_not_count_as_forced_eviction() {
815817
// Metric shouldn't show up at all, since it's zero the whole time.
816818
assert!(!body.contains("temporal_sticky_cache_total_forced_eviction"));
817819
}
820+
821+
#[tokio::test]
822+
async fn test_otel_errors_are_logged_as_errors() {
823+
// Create a subscriber that captures logs
824+
let collector = tracing_subscriber::fmt()
825+
.with_max_level(tracing::Level::ERROR)
826+
.with_test_writer()
827+
.finish();
828+
829+
// Set this subscriber as default
830+
let _guard = tracing::subscriber::set_default(collector);
831+
832+
let opts = OtelCollectorOptionsBuilder::default()
833+
// Intentionally invalid endpoint
834+
.url("http://localhost:9999/v1/metrics".parse().unwrap())
835+
// .protocol(OtlpProtocol::Http)
836+
.build()
837+
.unwrap();
838+
839+
// This exporter will fail every time it tries to export metrics
840+
let exporter = build_otlp_metric_exporter(opts).unwrap();
841+
842+
}
843+
844+
// use std::sync::{Arc, Mutex};
845+
// use std::time::Duration;
846+
// use temporal_sdk_core::{
847+
// CoreRuntime, TelemetryOptionsBuilder, telemetry::{build_otlp_metric_exporter, OtlpProtocol, OtelCollectorOptionsBuilder, CoreMeter},
848+
// };
849+
// use tracing_subscriber::fmt::MakeWriter;
850+
// use tracing::Level;
851+
// use tokio::time::sleep;
852+
853+
// A writer that captures logs into a buffer so we can assert on them.
854+
struct CapturingWriter {
855+
buf: Arc<Mutex<Vec<u8>>>,
856+
}
857+
858+
impl MakeWriter<'_> for CapturingWriter {
859+
type Writer = CapturingHandle;
860+
861+
fn make_writer(&self) -> Self::Writer {
862+
CapturingHandle(self.buf.clone())
863+
}
864+
}
865+
866+
struct CapturingHandle(Arc<Mutex<Vec<u8>>>);
867+
868+
impl std::io::Write for CapturingHandle {
869+
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
870+
let mut b = self.0.lock().unwrap();
871+
b.extend_from_slice(buf);
872+
Ok(buf.len())
873+
}
874+
fn flush(&mut self) -> std::io::Result<()> {
875+
Ok(())
876+
}
877+
}
878+
879+
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
880+
async fn test_otel_error_logged() {
881+
// Set up tracing subscriber to capture ERROR logs
882+
let logs = Arc::new(Mutex::new(Vec::new()));
883+
let writer = CapturingWriter { buf: logs.clone() };
884+
885+
let subscriber = tracing_subscriber::fmt()
886+
.with_max_level(tracing::Level::TRACE)
887+
.with_writer(writer)
888+
.finish();
889+
let _guard = tracing::subscriber::set_default(subscriber);
890+
891+
// Configure OTLP exporter with an invalid endpoint so it fails
892+
let opts = OtelCollectorOptionsBuilder::default()
893+
.url("http://localhost:9999/v1/metrics".parse().unwrap()) // Invalid endpoint
894+
// .protocol(OtlpProtocol::Http)
895+
.build()
896+
.unwrap();
897+
let exporter = build_otlp_metric_exporter(opts).unwrap();
898+
899+
let telemopts = TelemetryOptionsBuilder::default()
900+
.metrics(Arc::new(exporter) as Arc<dyn CoreMeter>)
901+
.build()
902+
.unwrap();
903+
904+
let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
905+
906+
let opts = get_integ_server_options();
907+
let mut raw_client = opts
908+
.connect_no_namespace(rt.telemetry().get_temporal_metric_meter())
909+
.await
910+
.unwrap();
911+
assert!(raw_client.get_client().capabilities().is_some());
912+
913+
let _ = raw_client
914+
.list_namespaces(ListNamespacesRequest::default())
915+
.await
916+
.unwrap();
917+
918+
// Trigger metric emission or just wait for exporter attempts
919+
// If you have a Temporal client to generate metrics, you can do so here.
920+
// For now, just wait to allow exporter to attempt sending metrics and fail.
921+
tokio::time::sleep(Duration::from_secs(5)).await;
922+
923+
924+
// Check the captured logs
925+
let logs = logs.lock().unwrap();
926+
let log_str = String::from_utf8_lossy(&logs);
927+
928+
// Assert that there is an error log
929+
assert!(
930+
log_str.contains("ERROR"),
931+
"Expected ERROR log not found in logs: {}",
932+
log_str
933+
);
934+
// Look for some substring that indicates OTLP export failed
935+
assert!(
936+
log_str.contains("failed") || log_str.contains("error"),
937+
"Expected an OTel exporter error message in logs: {}",
938+
log_str
939+
);
940+
}

0 commit comments

Comments
 (0)