open_lark/core/
observability.rs

1//! 可观测性模块
2//!
3//! 提供统一的日志记录、跟踪和监控功能
4
5use std::time::{Duration, Instant};
6use tracing::{span, Level, Span};
7use tracing_subscriber::{
8    fmt::{self, format::FmtSpan},
9    layer::SubscriberExt,
10    util::SubscriberInitExt,
11    EnvFilter, Registry,
12};
13
14#[cfg(feature = "otel")]
15use opentelemetry::trace::TracerProvider;
16#[cfg(feature = "otel")]
17use opentelemetry_otlp::WithExportConfig;
18#[cfg(feature = "otel")]
19use opentelemetry_sdk::{runtime, Resource};
20#[cfg(feature = "otel")]
21use tracing_opentelemetry::OpenTelemetryLayer;
22
23/// 操作跟踪器
24///
25/// 自动记录操作的开始、结束和持续时间
26pub struct OperationTracker {
27    span: Span,
28    start_time: Instant,
29    #[allow(dead_code)]
30    operation_name: String,
31}
32
33impl OperationTracker {
34    /// 开始跟踪一个操作
35    pub fn start(service_name: &str, operation_name: &str) -> Self {
36        let span = span!(
37            Level::INFO,
38            "service_operation",
39            service = service_name,
40            operation = operation_name,
41            duration_ms = tracing::field::Empty,
42            status = tracing::field::Empty,
43        );
44
45        {
46            let _enter = span.enter();
47            tracing::debug!("Starting operation");
48        }
49
50        Self {
51            span,
52            start_time: Instant::now(),
53            operation_name: operation_name.to_string(),
54        }
55    }
56
57    /// 标记操作成功完成
58    pub fn success(self) {
59        let duration = self.start_time.elapsed();
60        let duration_ms = duration.as_millis() as u64;
61
62        self.span.record("duration_ms", duration_ms);
63        self.span.record("status", "success");
64
65        let _enter = self.span.enter();
66        tracing::info!("Operation completed successfully");
67    }
68
69    /// 标记操作失败
70    pub fn error(self, error: &str) {
71        let duration = self.start_time.elapsed();
72        let duration_ms = duration.as_millis() as u64;
73
74        self.span.record("duration_ms", duration_ms);
75        self.span.record("status", "error");
76
77        let _enter = self.span.enter();
78        tracing::error!(error = error, "Operation failed");
79    }
80
81    /// 获取当前 span
82    pub fn span(&self) -> &Span {
83        &self.span
84    }
85
86    /// 获取操作已执行时间
87    pub fn elapsed(&self) -> Duration {
88        self.start_time.elapsed()
89    }
90}
91
92/// 初始化 tracing 基础设置
93pub fn init_tracing() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
94    init_tracing_with_filter("info")
95}
96
97/// 使用指定过滤器初始化 tracing
98pub fn init_tracing_with_filter(
99    filter: &str,
100) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
101    let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(filter));
102
103    let fmt_layer = fmt::layer()
104        .with_span_events(FmtSpan::ENTER | FmtSpan::CLOSE)
105        .with_target(true)
106        .with_thread_ids(true)
107        .with_thread_names(true);
108
109    Registry::default()
110        .with(env_filter)
111        .with(fmt_layer)
112        .try_init()?;
113
114    Ok(())
115}
116
117/// 初始化结构化 JSON 日志输出
118pub fn init_structured_tracing() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
119    let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
120
121    let json_layer = fmt::layer()
122        .json()
123        .with_current_span(true)
124        .with_span_list(true);
125
126    Registry::default()
127        .with(env_filter)
128        .with(json_layer)
129        .try_init()?;
130
131    Ok(())
132}
133
134/// OpenTelemetry 配置
135#[cfg(feature = "otel")]
136#[derive(Debug, Clone)]
137pub struct OtelConfig {
138    /// OTLP 端点 URL
139    pub endpoint: String,
140    /// 服务名称
141    pub service_name: String,
142    /// 服务版本
143    pub service_version: String,
144    /// 环境名称(dev, staging, prod)
145    pub environment: String,
146}
147
148#[cfg(feature = "otel")]
149impl Default for OtelConfig {
150    fn default() -> Self {
151        Self {
152            endpoint: "http://localhost:4317".to_string(),
153            service_name: "open-lark-sdk".to_string(),
154            service_version: env!("CARGO_PKG_VERSION").to_string(),
155            environment: "development".to_string(),
156        }
157    }
158}
159
160/// 初始化 OpenTelemetry + tracing
161#[cfg(feature = "otel")]
162pub fn init_otel_tracing(
163    config: Option<OtelConfig>,
164) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
165    let config = config.unwrap_or_default();
166
167    // 使用 0.24 API 创建 OTLP pipeline
168    let tracer_provider = opentelemetry_otlp::new_pipeline()
169        .tracing()
170        .with_exporter(
171            opentelemetry_otlp::new_exporter()
172                .tonic()
173                .with_endpoint(&config.endpoint),
174        )
175        .with_trace_config(opentelemetry_sdk::trace::Config::default().with_resource(
176            Resource::new(vec![
177                opentelemetry::KeyValue::new("service.name", config.service_name),
178                opentelemetry::KeyValue::new("service.version", config.service_version),
179                opentelemetry::KeyValue::new("environment", config.environment),
180            ]),
181        ))
182        .install_batch(runtime::Tokio)?;
183
184    // 设置全局 TracerProvider
185    opentelemetry::global::set_tracer_provider(tracer_provider.clone());
186
187    // 从 TracerProvider 获取 tracer(SDK 类型)
188    let tracer = tracer_provider.tracer("open-lark-sdk");
189
190    // 创建 OpenTelemetry 层
191    let otel_layer = OpenTelemetryLayer::new(tracer);
192
193    // 创建环境过滤器
194    let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
195
196    // 创建格式化层
197    let fmt_layer = fmt::layer()
198        .with_span_events(FmtSpan::ENTER | FmtSpan::CLOSE)
199        .with_target(true)
200        .with_thread_ids(true);
201
202    // 组合所有层
203    Registry::default()
204        .with(env_filter)
205        .with(fmt_layer)
206        .with(otel_layer)
207        .try_init()?;
208
209    Ok(())
210}
211
212/// 关闭 OpenTelemetry(确保数据被刷新)
213#[cfg(feature = "otel")]
214pub fn shutdown_otel() {
215    opentelemetry::global::shutdown_tracer_provider();
216}
217
218/// HTTP 请求跟踪
219pub struct HttpTracker {
220    span: Span,
221    start_time: Instant,
222}
223
224/// 认证操作跟踪器
225///
226/// 专门用于追踪token获取、刷新、验证等认证相关操作
227pub struct AuthTracker {
228    span: Span,
229    start_time: Instant,
230}
231
232impl AuthTracker {
233    /// 开始跟踪认证操作
234    pub fn start(operation_type: &str, app_id: &str, token_type: &str) -> Self {
235        let span = span!(
236            Level::INFO,
237            "auth_operation",
238            operation = operation_type,
239            app_id = app_id,
240            token_type = token_type,
241            cache_hit = tracing::field::Empty,
242            duration_ms = tracing::field::Empty,
243            success = tracing::field::Empty,
244            error_code = tracing::field::Empty,
245        );
246
247        {
248            let _enter = span.enter();
249            tracing::debug!("Starting authentication operation");
250        }
251
252        Self {
253            span,
254            start_time: Instant::now(),
255        }
256    }
257
258    /// 记录认证成功
259    pub fn success(self, cache_hit: bool) {
260        let duration = self.start_time.elapsed();
261        let duration_ms = duration.as_millis() as u64;
262
263        self.span.record("duration_ms", duration_ms);
264        self.span.record("success", true);
265        self.span.record("cache_hit", cache_hit);
266
267        let _enter = self.span.enter();
268        tracing::info!("Authentication operation completed successfully");
269    }
270
271    /// 记录认证失败
272    pub fn error(self, error: &str, error_code: Option<i32>) {
273        let duration = self.start_time.elapsed();
274        let duration_ms = duration.as_millis() as u64;
275
276        self.span.record("duration_ms", duration_ms);
277        self.span.record("success", false);
278
279        if let Some(code) = error_code {
280            self.span.record("error_code", code);
281        }
282
283        let _enter = self.span.enter();
284        tracing::error!(error = error, "Authentication operation failed");
285    }
286
287    /// 获取当前 span
288    pub fn span(&self) -> &Span {
289        &self.span
290    }
291}
292
293/// API响应处理跟踪器
294///
295/// 用于追踪响应解析、验证、转换等处理过程
296pub struct ResponseTracker {
297    span: Span,
298    start_time: Instant,
299}
300
301impl ResponseTracker {
302    /// 开始跟踪响应处理
303    pub fn start(response_format: &str, response_size: Option<u64>) -> Self {
304        let span = span!(
305            Level::DEBUG,
306            "response_processing",
307            format = response_format,
308            input_size = response_size.unwrap_or(0),
309            parsing_duration_ms = tracing::field::Empty,
310            validation_duration_ms = tracing::field::Empty,
311            total_duration_ms = tracing::field::Empty,
312            success = tracing::field::Empty,
313        );
314
315        {
316            let _enter = span.enter();
317            tracing::debug!("Starting response processing");
318        }
319
320        Self {
321            span,
322            start_time: Instant::now(),
323        }
324    }
325
326    /// 记录解析阶段完成
327    pub fn parsing_complete(&self) {
328        let parsing_duration = self.start_time.elapsed();
329        let parsing_duration_ms = parsing_duration.as_millis() as u64;
330        self.span.record("parsing_duration_ms", parsing_duration_ms);
331    }
332
333    /// 记录验证阶段完成
334    pub fn validation_complete(&self) {
335        let total_duration = self.start_time.elapsed();
336        let validation_duration_ms = total_duration.as_millis() as u64;
337        self.span
338            .record("validation_duration_ms", validation_duration_ms);
339    }
340
341    /// 记录处理成功
342    pub fn success(self) {
343        let duration = self.start_time.elapsed();
344        let duration_ms = duration.as_millis() as u64;
345
346        self.span.record("total_duration_ms", duration_ms);
347        self.span.record("success", true);
348
349        let _enter = self.span.enter();
350        tracing::debug!("Response processing completed successfully");
351    }
352
353    /// 记录处理失败
354    pub fn error(self, error: &str) {
355        let duration = self.start_time.elapsed();
356        let duration_ms = duration.as_millis() as u64;
357
358        self.span.record("total_duration_ms", duration_ms);
359        self.span.record("success", false);
360
361        let _enter = self.span.enter();
362        tracing::error!(error = error, "Response processing failed");
363    }
364}
365
366impl HttpTracker {
367    /// 开始跟踪 HTTP 请求
368    pub fn start(method: &str, url: &str) -> Self {
369        let span = span!(
370            Level::INFO,
371            "http_request",
372            method = method,
373            url = url,
374            status_code = tracing::field::Empty,
375            duration_ms = tracing::field::Empty,
376            response_size = tracing::field::Empty,
377        );
378
379        {
380            let _enter = span.enter();
381            tracing::debug!("Sending HTTP request");
382        }
383
384        Self {
385            span,
386            start_time: Instant::now(),
387        }
388    }
389
390    /// 记录响应完成
391    pub fn response(self, status_code: u16, response_size: Option<u64>) {
392        let duration = self.start_time.elapsed();
393        let duration_ms = duration.as_millis() as u64;
394
395        self.span.record("status_code", status_code);
396        self.span.record("duration_ms", duration_ms);
397
398        if let Some(size) = response_size {
399            self.span.record("response_size", size);
400        }
401
402        let _enter = self.span.enter();
403        if (200..300).contains(&status_code) {
404            tracing::info!("HTTP request completed successfully");
405        } else if status_code >= 400 {
406            tracing::warn!("HTTP request failed");
407        } else {
408            tracing::info!("HTTP request completed");
409        }
410    }
411
412    /// 记录请求错误
413    pub fn error(self, error: &str) {
414        let duration = self.start_time.elapsed();
415        let duration_ms = duration.as_millis() as u64;
416
417        self.span.record("duration_ms", duration_ms);
418
419        let _enter = self.span.enter();
420        tracing::error!(error = error, "HTTP request failed");
421    }
422}
423
424/// 性能监控宏
425///
426/// 自动跟踪代码块的执行时间
427#[macro_export]
428macro_rules! trace_performance {
429    ($name:expr, $code:block) => {{
430        let _tracker = $crate::core::observability::OperationTracker::start("performance", $name);
431        let result = $code;
432        _tracker.success();
433        result
434    }};
435    ($service:expr, $operation:expr, $code:block) => {{
436        let _tracker = $crate::core::observability::OperationTracker::start($service, $operation);
437        let result = $code;
438        _tracker.success();
439        result
440    }};
441}
442
443/// 异步性能监控宏
444#[macro_export]
445macro_rules! trace_async_performance {
446    ($name:expr, $code:expr) => {{
447        let tracker = $crate::core::observability::OperationTracker::start("performance", $name);
448        match $code.await {
449            Ok(result) => {
450                tracker.success();
451                Ok(result)
452            }
453            Err(err) => {
454                tracker.error(&err.to_string());
455                Err(err)
456            }
457        }
458    }};
459    ($service:expr, $operation:expr, $code:expr) => {{
460        let tracker = $crate::core::observability::OperationTracker::start($service, $operation);
461        match $code.await {
462            Ok(result) => {
463                tracker.success();
464                Ok(result)
465            }
466            Err(err) => {
467                tracker.error(&err.to_string());
468                Err(err)
469            }
470        }
471    }};
472}
473
474/// 认证操作跟踪宏
475///
476/// 简化在认证流程中添加可观测性的过程
477#[macro_export]
478macro_rules! trace_auth_operation {
479    ($operation:expr, $app_id:expr, $token_type:expr, $code:expr) => {
480        async move {
481            let tracker =
482                $crate::core::observability::AuthTracker::start($operation, $app_id, $token_type);
483            match $code.await {
484                Ok((result, cache_hit)) => {
485                    tracker.success(cache_hit);
486                    Ok(result)
487                }
488                Err(err) => {
489                    // 尝试从错误中提取错误码
490                    let error_code =
491                        if let $crate::core::error::LarkAPIError::APIError { code, .. } = &err {
492                            Some(*code)
493                        } else {
494                            None
495                        };
496                    tracker.error(&err.to_string(), error_code);
497                    Err(err)
498                }
499            }
500        }
501    };
502}
503
504/// HTTP请求跟踪宏
505///
506/// 为HTTP请求添加完整的可观测性
507#[macro_export]
508macro_rules! trace_http_request {
509    ($method:expr, $url:expr, $code:expr) => {
510        async move {
511            let tracker = $crate::core::observability::HttpTracker::start($method, $url);
512            match $code.await {
513                Ok(response) => {
514                    let status_code = if let Ok(status) = response.status() {
515                        status.as_u16()
516                    } else {
517                        0
518                    };
519                    tracker.response(status_code, None);
520                    Ok(response)
521                }
522                Err(err) => {
523                    tracker.error(&err.to_string());
524                    Err(err)
525                }
526            }
527        }
528    };
529}
530
531/// 响应处理跟踪宏
532///
533/// 为响应解析和处理添加可观测性
534#[macro_export]
535macro_rules! trace_response_processing {
536    ($format:expr, $size:expr, $parsing:expr, $validation:expr) => {{
537        let tracker = $crate::core::observability::ResponseTracker::start($format, $size);
538
539        // 解析阶段
540        let parsed_result = $parsing;
541        tracker.parsing_complete();
542
543        match parsed_result {
544            Ok(parsed_data) => {
545                // 验证阶段
546                match $validation(parsed_data) {
547                    Ok(validated_data) => {
548                        tracker.validation_complete();
549                        tracker.success();
550                        Ok(validated_data)
551                    }
552                    Err(err) => {
553                        tracker.error(&err.to_string());
554                        Err(err)
555                    }
556                }
557            }
558            Err(err) => {
559                tracker.error(&err.to_string());
560                Err(err)
561            }
562        }
563    }};
564}
565
566/// 服务健康检查跟踪
567pub fn trace_health_check<F, T>(service_name: &str, check_fn: F) -> T
568where
569    F: FnOnce() -> T,
570{
571    let tracker = OperationTracker::start(service_name, "health_check");
572    let result = check_fn();
573    tracker.success();
574    result
575}
576
577/// 异步服务健康检查跟踪
578pub async fn trace_async_health_check<F, Fut, T, E>(service_name: &str, check_fn: F) -> Result<T, E>
579where
580    F: FnOnce() -> Fut,
581    Fut: std::future::Future<Output = Result<T, E>>,
582    E: std::fmt::Display,
583{
584    let tracker = OperationTracker::start(service_name, "health_check");
585    match check_fn().await {
586        Ok(result) => {
587            tracker.success();
588            Ok(result)
589        }
590        Err(err) => {
591            tracker.error(&err.to_string());
592            Err(err)
593        }
594    }
595}
596
597#[cfg(test)]
598mod tests {
599    use super::*;
600    use std::time::Duration;
601    use tracing_test::traced_test;
602
603    #[traced_test]
604    #[test]
605    fn test_operation_tracker_success() {
606        let tracker = OperationTracker::start("test_service", "test_operation");
607        std::thread::sleep(Duration::from_millis(10));
608
609        // 确保已过去一些时间
610        assert!(tracker.elapsed() >= Duration::from_millis(10));
611
612        tracker.success();
613
614        // 验证日志是否记录
615        assert!(logs_contain("Starting operation"));
616        assert!(logs_contain("Operation completed successfully"));
617    }
618
619    #[traced_test]
620    #[test]
621    fn test_operation_tracker_error() {
622        let tracker = OperationTracker::start("test_service", "test_operation");
623        tracker.error("Test error message");
624
625        // 验证错误日志是否记录
626        assert!(logs_contain("Operation failed"));
627        assert!(logs_contain("Test error message"));
628    }
629
630    #[traced_test]
631    #[test]
632    fn test_http_tracker() {
633        let tracker = HttpTracker::start("GET", "https://api.example.com/test");
634        tracker.response(200, Some(1024));
635
636        // 验证 HTTP 请求日志
637        assert!(logs_contain("Sending HTTP request"));
638        assert!(logs_contain("HTTP request completed successfully"));
639    }
640
641    #[traced_test]
642    #[test]
643    fn test_performance_macro() {
644        let result = trace_performance!("test_perf", {
645            std::thread::sleep(Duration::from_millis(5));
646            42
647        });
648
649        assert_eq!(result, 42);
650        assert!(logs_contain("Starting operation"));
651        assert!(logs_contain("Operation completed successfully"));
652    }
653
654    #[traced_test]
655    #[tokio::test]
656    async fn test_async_performance_macro() {
657        let result: Result<i32, &str> =
658            trace_async_performance!("test_service", "async_op", async {
659                tokio::time::sleep(Duration::from_millis(5)).await;
660                Ok::<i32, &str>(42)
661            });
662
663        assert_eq!(result.unwrap(), 42);
664        assert!(logs_contain("Starting operation"));
665        assert!(logs_contain("Operation completed successfully"));
666    }
667
668    #[traced_test]
669    #[test]
670    fn test_trace_health_check() {
671        let result = trace_health_check("test_service", || "healthy");
672
673        assert_eq!(result, "healthy");
674        assert!(logs_contain("Starting operation"));
675        assert!(logs_contain("Operation completed successfully"));
676    }
677
678    #[traced_test]
679    #[tokio::test]
680    async fn test_trace_async_health_check_success() {
681        let result =
682            trace_async_health_check("test_service", || async { Ok::<&str, &str>("healthy") })
683                .await;
684
685        assert_eq!(result.unwrap(), "healthy");
686        assert!(logs_contain("Starting operation"));
687        assert!(logs_contain("Operation completed successfully"));
688    }
689
690    #[traced_test]
691    #[tokio::test]
692    async fn test_trace_async_health_check_error() {
693        let result =
694            trace_async_health_check("test_service", || async { Err::<&str, &str>("unhealthy") })
695                .await;
696
697        assert!(result.is_err());
698        assert!(logs_contain("Starting operation"));
699        assert!(logs_contain("Operation failed"));
700        assert!(logs_contain("unhealthy"));
701    }
702
703    #[traced_test]
704    #[test]
705    fn test_auth_tracker_success() {
706        let tracker = AuthTracker::start("get_token", "test_app", "tenant");
707        std::thread::sleep(Duration::from_millis(10));
708
709        // 模拟缓存命中
710        tracker.success(true);
711
712        // 验证认证操作日志
713        assert!(logs_contain("Starting authentication operation"));
714        assert!(logs_contain(
715            "Authentication operation completed successfully"
716        ));
717    }
718
719    #[traced_test]
720    #[test]
721    fn test_auth_tracker_error() {
722        let tracker = AuthTracker::start("refresh_token", "test_app", "user");
723        tracker.error("Invalid credentials", Some(401));
724
725        // 验证认证错误日志
726        assert!(logs_contain("Starting authentication operation"));
727        assert!(logs_contain("Authentication operation failed"));
728        assert!(logs_contain("Invalid credentials"));
729    }
730
731    #[traced_test]
732    #[test]
733    fn test_response_tracker() {
734        let tracker = ResponseTracker::start("json", Some(1024));
735        std::thread::sleep(Duration::from_millis(5));
736
737        // 模拟解析完成
738        tracker.parsing_complete();
739        std::thread::sleep(Duration::from_millis(3));
740
741        // 模拟验证完成
742        tracker.validation_complete();
743
744        // 完成处理
745        tracker.success();
746
747        // 验证响应处理日志
748        assert!(logs_contain("Starting response processing"));
749        assert!(logs_contain("Response processing completed successfully"));
750    }
751
752    #[traced_test]
753    #[test]
754    fn test_response_tracker_error() {
755        let tracker = ResponseTracker::start("xml", Some(512));
756        tracker.error("Parse error: invalid XML structure");
757
758        // 验证响应处理错误日志
759        assert!(logs_contain("Starting response processing"));
760        assert!(logs_contain("Response processing failed"));
761        assert!(logs_contain("Parse error: invalid XML structure"));
762    }
763
764    #[traced_test]
765    #[tokio::test]
766    async fn test_trace_auth_operation_macro() {
767        use crate::core::error::LarkAPIError;
768
769        // 测试成功场景 - 需要返回元组 (结果, 是否缓存命中)
770        let result = trace_auth_operation!("get_app_token", "test_app", "app", async {
771            Ok::<(String, bool), LarkAPIError>(("token_value".to_string(), true))
772        })
773        .await;
774
775        assert!(result.is_ok());
776        assert!(logs_contain("Starting authentication operation"));
777        assert!(logs_contain(
778            "Authentication operation completed successfully"
779        ));
780    }
781
782    #[traced_test]
783    #[tokio::test]
784    async fn test_trace_response_processing_macro() {
785        // 测试响应处理宏
786        let format = "json";
787        let size = Some(256_u64);
788
789        let parsing_fn = || Ok::<String, std::io::Error>("parsed_data".to_string());
790        let validation_fn = |data: String| {
791            if data.is_empty() {
792                Err(std::io::Error::new(
793                    std::io::ErrorKind::InvalidData,
794                    "Empty data",
795                ))
796            } else {
797                Ok(data)
798            }
799        };
800
801        let result = trace_response_processing!(format, size, parsing_fn(), validation_fn);
802
803        assert!(result.is_ok());
804        assert_eq!(result.unwrap(), "parsed_data");
805        assert!(logs_contain("Starting response processing"));
806        assert!(logs_contain("Response processing completed successfully"));
807    }
808
809    // Additional comprehensive tests for better coverage
810
811    #[traced_test]
812    #[test]
813    fn test_operation_tracker_span_access() {
814        let tracker = OperationTracker::start("test_service", "test_operation");
815
816        // Test span access
817        let span = tracker.span();
818        assert!(!span.is_disabled());
819
820        // Test elapsed time access
821        let elapsed = tracker.elapsed();
822        assert!(elapsed >= Duration::from_nanos(0));
823
824        tracker.success();
825    }
826
827    #[traced_test]
828    #[test]
829    fn test_auth_tracker_span_access() {
830        let tracker = AuthTracker::start("get_token", "test_app", "tenant");
831
832        // Test span access
833        let span = tracker.span();
834        assert!(!span.is_disabled());
835
836        tracker.success(false); // Test with cache miss
837
838        assert!(logs_contain("Starting authentication operation"));
839        assert!(logs_contain(
840            "Authentication operation completed successfully"
841        ));
842    }
843
844    #[traced_test]
845    #[test]
846    fn test_auth_tracker_error_without_code() {
847        let tracker = AuthTracker::start("refresh_token", "test_app", "user");
848        tracker.error("Network timeout", None); // No error code
849
850        assert!(logs_contain("Authentication operation failed"));
851        assert!(logs_contain("Network timeout"));
852    }
853
854    #[traced_test]
855    #[test]
856    fn test_http_tracker_different_status_codes() {
857        // Test successful 2xx status
858        let tracker1 = HttpTracker::start("GET", "https://api.example.com/users");
859        tracker1.response(201, Some(512));
860        assert!(logs_contain("HTTP request completed successfully"));
861
862        // Test redirection 3xx status
863        let tracker2 = HttpTracker::start("GET", "https://api.example.com/redirect");
864        tracker2.response(302, None);
865        assert!(logs_contain("HTTP request completed"));
866
867        // Test client error 4xx status
868        let tracker3 = HttpTracker::start("POST", "https://api.example.com/invalid");
869        tracker3.response(404, Some(128));
870        assert!(logs_contain("HTTP request failed"));
871
872        // Test server error 5xx status
873        let tracker4 = HttpTracker::start("PUT", "https://api.example.com/error");
874        tracker4.response(500, Some(256));
875        assert!(logs_contain("HTTP request failed"));
876    }
877
878    #[traced_test]
879    #[test]
880    fn test_http_tracker_network_error() {
881        let tracker = HttpTracker::start("GET", "https://api.example.com/timeout");
882        tracker.error("Connection timeout after 30 seconds");
883
884        assert!(logs_contain("Sending HTTP request"));
885        assert!(logs_contain("HTTP request failed"));
886        assert!(logs_contain("Connection timeout after 30 seconds"));
887    }
888
889    #[traced_test]
890    #[test]
891    fn test_response_tracker_with_none_size() {
892        let tracker = ResponseTracker::start("xml", None);
893
894        // Test parsing without validation
895        tracker.parsing_complete();
896        tracker.success();
897
898        assert!(logs_contain("Starting response processing"));
899        assert!(logs_contain("Response processing completed successfully"));
900    }
901
902    #[traced_test]
903    #[test]
904    fn test_response_tracker_validation_timing() {
905        let tracker = ResponseTracker::start("binary", Some(2048));
906
907        // Test timing sequence
908        std::thread::sleep(Duration::from_millis(2));
909        tracker.parsing_complete();
910
911        std::thread::sleep(Duration::from_millis(3));
912        tracker.validation_complete();
913
914        std::thread::sleep(Duration::from_millis(1));
915        tracker.success();
916
917        assert!(logs_contain("Starting response processing"));
918        assert!(logs_contain("Response processing completed successfully"));
919    }
920
921    #[traced_test]
922    #[tokio::test]
923    async fn test_async_performance_macro_error() {
924        let result: Result<i32, &str> =
925            trace_async_performance!("test_service", "failing_op", async {
926                tokio::time::sleep(Duration::from_millis(2)).await;
927                Err::<i32, &str>("Operation failed")
928            });
929
930        assert!(result.is_err());
931        assert_eq!(result.unwrap_err(), "Operation failed");
932        assert!(logs_contain("Starting operation"));
933        assert!(logs_contain("Operation failed"));
934    }
935
936    #[traced_test]
937    #[test]
938    fn test_performance_macro_with_service_and_operation() {
939        let result = trace_performance!("my_service", "complex_operation", {
940            std::thread::sleep(Duration::from_millis(1));
941            "result"
942        });
943
944        assert_eq!(result, "result");
945        assert!(logs_contain("Starting operation"));
946        assert!(logs_contain("Operation completed successfully"));
947    }
948
949    #[traced_test]
950    #[tokio::test]
951    async fn test_trace_auth_operation_macro_error() {
952        use crate::core::error::LarkAPIError;
953
954        // Test error scenario with API error code
955        let result = trace_auth_operation!("get_tenant_token", "test_app", "tenant", async {
956            Err::<(String, bool), LarkAPIError>(LarkAPIError::APIError {
957                code: 10001,
958                msg: "App not found".to_string(),
959                error: None,
960            })
961        })
962        .await;
963
964        assert!(result.is_err());
965        assert!(logs_contain("Starting authentication operation"));
966        assert!(logs_contain("Authentication operation failed"));
967        assert!(logs_contain("App not found"));
968    }
969
970    #[traced_test]
971    #[tokio::test]
972    async fn test_trace_auth_operation_macro_non_api_error() {
973        use crate::core::error::LarkAPIError;
974
975        // Test with non-API error (no error code)
976        let result = trace_auth_operation!("validate_token", "test_app", "user", async {
977            Err::<(String, bool), LarkAPIError>(LarkAPIError::RequestError(
978                "Network connection failed".to_string(),
979            ))
980        })
981        .await;
982
983        assert!(result.is_err());
984        assert!(logs_contain("Starting authentication operation"));
985        assert!(logs_contain("Authentication operation failed"));
986        assert!(logs_contain("Network connection failed"));
987    }
988
989    #[traced_test]
990    #[test]
991    fn test_trace_response_processing_macro_parsing_error() {
992        let format = "yaml";
993        let size = Some(128_u64);
994
995        let parsing_fn = || {
996            Err::<String, std::io::Error>(std::io::Error::new(
997                std::io::ErrorKind::InvalidData,
998                "Invalid YAML syntax",
999            ))
1000        };
1001        let validation_fn = |data: String| Ok::<String, std::io::Error>(data);
1002
1003        let result = trace_response_processing!(format, size, parsing_fn(), validation_fn);
1004
1005        assert!(result.is_err());
1006        assert!(logs_contain("Starting response processing"));
1007        assert!(logs_contain("Response processing failed"));
1008        assert!(logs_contain("Invalid YAML syntax"));
1009    }
1010
1011    #[traced_test]
1012    #[test]
1013    fn test_trace_response_processing_macro_validation_error() {
1014        let format = "csv";
1015        let size = Some(64_u64);
1016
1017        let parsing_fn = || Ok::<String, std::io::Error>("".to_string()); // Empty data
1018        let validation_fn = |data: String| {
1019            if data.is_empty() {
1020                Err(std::io::Error::new(
1021                    std::io::ErrorKind::InvalidData,
1022                    "CSV data cannot be empty",
1023                ))
1024            } else {
1025                Ok(data)
1026            }
1027        };
1028
1029        let result = trace_response_processing!(format, size, parsing_fn(), validation_fn);
1030
1031        assert!(result.is_err());
1032        assert!(logs_contain("Starting response processing"));
1033        assert!(logs_contain("Response processing failed"));
1034        assert!(logs_contain("CSV data cannot be empty"));
1035    }
1036
1037    #[test]
1038    fn test_init_tracing_functions() {
1039        // Note: These functions are hard to test in unit tests because they affect global state
1040        // We can test that they don't panic and return Ok/Err appropriately
1041
1042        // Test that multiple initializations handle gracefully
1043        // (tracing_subscriber typically returns an error on re-initialization)
1044        let result1 = init_tracing();
1045        let result2 = init_tracing_with_filter("debug");
1046        let result3 = init_structured_tracing();
1047
1048        // At least one should succeed (the first one) or all should handle errors gracefully
1049        // We don't assert specific Ok/Err because the global state affects this
1050        assert!(result1.is_ok() || result1.is_err()); // Either outcome is acceptable
1051        assert!(result2.is_ok() || result2.is_err());
1052        assert!(result3.is_ok() || result3.is_err());
1053    }
1054
1055    #[cfg(feature = "otel")]
1056    #[test]
1057    fn test_otel_config_default() {
1058        let config = OtelConfig::default();
1059
1060        assert_eq!(config.endpoint, "http://localhost:4317");
1061        assert_eq!(config.service_name, "open-lark-sdk");
1062        assert_eq!(config.service_version, env!("CARGO_PKG_VERSION"));
1063        assert_eq!(config.environment, "development");
1064    }
1065
1066    #[cfg(feature = "otel")]
1067    #[test]
1068    fn test_otel_config_custom() {
1069        let config = OtelConfig {
1070            endpoint: "https://otel.example.com:4317".to_string(),
1071            service_name: "custom-service".to_string(),
1072            service_version: "1.2.3".to_string(),
1073            environment: "production".to_string(),
1074        };
1075
1076        assert_eq!(config.endpoint, "https://otel.example.com:4317");
1077        assert_eq!(config.service_name, "custom-service");
1078        assert_eq!(config.service_version, "1.2.3");
1079        assert_eq!(config.environment, "production");
1080    }
1081
1082    #[cfg(feature = "otel")]
1083    #[test]
1084    fn test_otel_config_clone_and_debug() {
1085        let config = OtelConfig::default();
1086        let cloned_config = config.clone();
1087
1088        assert_eq!(config.endpoint, cloned_config.endpoint);
1089        assert_eq!(config.service_name, cloned_config.service_name);
1090
1091        let debug_str = format!("{:?}", config);
1092        assert!(debug_str.contains("OtelConfig"));
1093        assert!(debug_str.contains("endpoint"));
1094        assert!(debug_str.contains("service_name"));
1095    }
1096
1097    // Note: init_otel_tracing and shutdown_otel are hard to test in unit tests
1098    // because they require actual OpenTelemetry infrastructure and affect global state
1099    // These would be better tested in integration tests
1100
1101    #[traced_test]
1102    #[test]
1103    fn test_operation_tracker_zero_elapsed_time() {
1104        let tracker = OperationTracker::start("instant_service", "instant_operation");
1105        // Don't sleep, test immediate completion
1106        let elapsed = tracker.elapsed();
1107        tracker.success();
1108
1109        // Should have some minimal elapsed time
1110        assert!(elapsed >= Duration::from_nanos(0));
1111        assert!(logs_contain("Starting operation"));
1112        assert!(logs_contain("Operation completed successfully"));
1113    }
1114
1115    #[traced_test]
1116    #[test]
1117    fn test_multiple_trackers_concurrent() {
1118        let tracker1 = OperationTracker::start("service1", "operation1");
1119        let tracker2 = AuthTracker::start("auth_op", "app1", "tenant");
1120        let tracker3 = HttpTracker::start("POST", "https://example.com/api");
1121        let tracker4 = ResponseTracker::start("json", Some(1024));
1122
1123        // Complete in different orders
1124        tracker2.success(true);
1125        tracker4.success();
1126        tracker1.success();
1127        tracker3.response(200, Some(512));
1128
1129        // All should log successfully
1130        assert!(logs_contain("Starting operation"));
1131        assert!(logs_contain("Starting authentication operation"));
1132        assert!(logs_contain("Sending HTTP request"));
1133        assert!(logs_contain("Starting response processing"));
1134    }
1135
1136    #[traced_test]
1137    #[test]
1138    fn test_edge_case_empty_strings() {
1139        let tracker1 = OperationTracker::start("", "");
1140        tracker1.success();
1141
1142        let tracker2 = AuthTracker::start("", "", "");
1143        tracker2.error("", None);
1144
1145        let tracker3 = HttpTracker::start("", "");
1146        tracker3.error("");
1147
1148        let tracker4 = ResponseTracker::start("", Some(0));
1149        tracker4.error("");
1150
1151        // Should handle empty strings gracefully
1152        assert!(logs_contain("Starting operation"));
1153        assert!(logs_contain("Starting authentication operation"));
1154        assert!(logs_contain("Sending HTTP request"));
1155        assert!(logs_contain("Starting response processing"));
1156    }
1157}