@@ -10,7 +10,7 @@ use opentelemetry_proto::tonic::logs::v1::LogRecord;
1010use opentelemetry_proto:: tonic:: trace:: v1:: Span ;
1111use std:: borrow:: Cow ;
1212use std:: sync:: Arc ;
13- use tracing:: debug;
13+ use tracing:: { debug, error } ;
1414
1515const FIELD_ENV_NAME : & str = "env_name" ;
1616const FIELD_ENV_VER : & str = "env_ver" ;
@@ -82,7 +82,8 @@ impl OtlpEncoder {
8282 acc. push ( ';' ) ;
8383 }
8484 let md5_hash = md5:: compute ( s. id . to_le_bytes ( ) ) ;
85- write ! ( & mut acc, "{md5_hash:x}" ) . unwrap ( ) ;
85+ // Writing to String never fails in practice, ignore error
86+ let _ = write ! ( & mut acc, "{md5_hash:x}" ) ;
8687 acc
8788 } ,
8889 )
@@ -273,7 +274,8 @@ impl OtlpEncoder {
273274 acc. push ( ';' ) ;
274275 }
275276 let md5_hash = md5:: compute ( s. id . to_le_bytes ( ) ) ;
276- write ! ( & mut acc, "{md5_hash:x}" ) . unwrap ( ) ;
277+ // Writing to String never fails in practice, ignore error
278+ let _ = write ! ( & mut acc, "{md5_hash:x}" ) ;
277279 acc
278280 } ,
279281 )
@@ -568,12 +570,14 @@ impl OtlpEncoder {
568570 }
569571 FIELD_TRACE_ID => {
570572 let hex_bytes = Self :: encode_id_to_hex :: < 32 > ( & span. trace_id ) ;
571- let hex_str = std:: str:: from_utf8 ( & hex_bytes) . unwrap ( ) ;
573+ let hex_str = std:: str:: from_utf8 ( & hex_bytes)
574+ . expect ( "hex encoding always produces valid UTF-8" ) ;
572575 BondWriter :: write_string ( & mut buffer, hex_str) ;
573576 }
574577 FIELD_SPAN_ID => {
575578 let hex_bytes = Self :: encode_id_to_hex :: < 16 > ( & span. span_id ) ;
576- let hex_str = std:: str:: from_utf8 ( & hex_bytes) . unwrap ( ) ;
579+ let hex_str = std:: str:: from_utf8 ( & hex_bytes)
580+ . expect ( "hex encoding always produces valid UTF-8" ) ;
577581 BondWriter :: write_string ( & mut buffer, hex_str) ;
578582 }
579583 FIELD_TRACE_FLAGS => {
@@ -587,7 +591,8 @@ impl OtlpEncoder {
587591 }
588592 FIELD_PARENT_ID => {
589593 let hex_bytes = Self :: encode_id_to_hex :: < 16 > ( & span. parent_span_id ) ;
590- let hex_str = std:: str:: from_utf8 ( & hex_bytes) . unwrap ( ) ;
594+ let hex_str = std:: str:: from_utf8 ( & hex_bytes)
595+ . expect ( "hex encoding always produces valid UTF-8" ) ;
591596 BondWriter :: write_string ( & mut buffer, hex_str) ;
592597 }
593598 FIELD_LINKS => {
@@ -636,12 +641,14 @@ impl OtlpEncoder {
636641 }
637642 FIELD_TRACE_ID => {
638643 let hex_bytes = Self :: encode_id_to_hex :: < 32 > ( & log. trace_id ) ;
639- let hex_str = std:: str:: from_utf8 ( & hex_bytes) . unwrap ( ) ;
644+ let hex_str = std:: str:: from_utf8 ( & hex_bytes)
645+ . expect ( "hex encoding always produces valid UTF-8" ) ;
640646 BondWriter :: write_string ( & mut buffer, hex_str) ;
641647 }
642648 FIELD_SPAN_ID => {
643649 let hex_bytes = Self :: encode_id_to_hex :: < 16 > ( & log. span_id ) ;
644- let hex_str = std:: str:: from_utf8 ( & hex_bytes) . unwrap ( ) ;
650+ let hex_str = std:: str:: from_utf8 ( & hex_bytes)
651+ . expect ( "hex encoding always produces valid UTF-8" ) ;
645652 BondWriter :: write_string ( & mut buffer, hex_str) ;
646653 }
647654 FIELD_TRACE_FLAGS => {
@@ -679,7 +686,23 @@ impl OtlpEncoder {
679686
680687 fn encode_id_to_hex < const N : usize > ( id : & [ u8 ] ) -> [ u8 ; N ] {
681688 let mut hex_bytes = [ 0u8 ; N ] ;
682- hex:: encode_to_slice ( id, & mut hex_bytes) . unwrap ( ) ;
689+ // If encoding fails (buffer size mismatch), log error and return zeros
690+ if let Err ( e) = hex:: encode_to_slice ( id, & mut hex_bytes) {
691+ let id_type = match N {
692+ 32 => "trace ID" ,
693+ 16 => "span ID" ,
694+ _ => "input" ,
695+ } ;
696+ error ! (
697+ name: "encoder.encode_id_to_hex.error" ,
698+ target: "geneva-uploader" ,
699+ error = %e,
700+ id_len = id. len( ) ,
701+ buffer_size = N ,
702+ "Hex encoding failed, using zeros - indicates an invalid {}" ,
703+ id_type
704+ ) ;
705+ }
683706 hex_bytes
684707 }
685708
@@ -722,14 +745,25 @@ impl OtlpEncoder {
722745 json
723746 }
724747
725- /// Format timestamp from nanoseconds
748+ /// Format timestamp from nanoseconds to RFC3339 string
726749 fn format_timestamp ( nanos : u64 ) -> String {
727750 let secs = ( nanos / 1_000_000_000 ) as i64 ;
728751 let nsec = ( nanos % 1_000_000_000 ) as u32 ;
729- Utc . timestamp_opt ( secs, nsec)
730- . single ( )
731- . unwrap_or_else ( || Utc . timestamp_opt ( 0 , 0 ) . single ( ) . unwrap ( ) )
732- . to_rfc3339 ( )
752+
753+ match Utc . timestamp_opt ( secs, nsec) . single ( ) {
754+ Some ( dt) => dt. to_rfc3339 ( ) ,
755+ None => {
756+ error ! (
757+ name: "encoder.format_timestamp.invalid" ,
758+ target: "geneva-uploader" ,
759+ nanos = nanos,
760+ secs = secs,
761+ nsec = nsec,
762+ "Timestamp out of range, using epoch"
763+ ) ;
764+ "1970-01-01T00:00:00+00:00" . to_string ( )
765+ }
766+ }
733767 }
734768
735769 /// Write attribute value based on its type
0 commit comments