Convert opencode transcripts to otel (or agent) traces
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Use log 'updated at' timestamp instead of individual span timestamps

- Parse 'updated' field from OpenCodeLog header
- Pass updated_at timestamp to all export functions
- Use updated_at for span timing, falling back to span timestamp if needed
- Simplifies timestamp handling by using single reference point

rektide ddffc614 32c3129a

+18 -11
+5 -1
src/commands/export.rs
··· 1 1 use anyhow::{Context, Result}; 2 + use jiff::Timestamp; 3 + use std::str::FromStr; 2 4 3 5 use crate::cli::{ExportArgs, OtlpProtocol, OutputFormat}; 4 6 use crate::config::{OtlpConfig, OtlpProtocol as ConfigOtlpProtocol}; ··· 49 51 50 52 let filtered_entries = entries; 51 53 54 + let updated_at = Timestamp::from_str(&log.updated).ok(); 55 + 52 56 if use_stdout { 53 57 tracing::info!("Outputting {} spans to stdout in {:?} format", filtered_entries.len(), output_format); 54 58 let output = formatter::format_spans(&filtered_entries, output_format)?; ··· 65 69 tracing::info!("Exporting {} spans...", filtered_entries.len()); 66 70 67 71 for entry in &filtered_entries { 68 - exporter.export_log(entry); 72 + exporter.export_log(entry, updated_at.as_ref()); 69 73 } 70 74 71 75 tracing::info!("Flushing pending spans...");
+13 -10
src/exporter.rs
··· 116 116 Ok((tracer, provider)) 117 117 } 118 118 119 - pub fn export_log(&self, span: &GenAiSpan) { 119 + pub fn export_log(&self, span: &GenAiSpan, updated_at: Option<&Timestamp>) { 120 120 match span.span_type { 121 - SpanType::ToolCall => self.export_tool_call(span), 122 - SpanType::Chat => self.export_chat(span), 123 - SpanType::Thinking => self.export_thinking(span), 121 + SpanType::ToolCall => self.export_tool_call(span, updated_at), 122 + SpanType::Chat => self.export_chat(span, updated_at), 123 + SpanType::Thinking => self.export_thinking(span, updated_at), 124 124 } 125 125 } 126 126 127 - fn export_tool_call(&self, span: &GenAiSpan) { 127 + fn export_tool_call(&self, span: &GenAiSpan, updated_at: Option<&Timestamp>) { 128 128 let mut attributes = vec![ 129 129 KeyValue::new("gen_ai.conversation.id", span.session_id.clone()), 130 130 KeyValue::new("network.transport", "tcp"), ··· 167 167 builder.span_kind = Some(SpanKind::Client); 168 168 builder.attributes = Some(attributes); 169 169 170 - let start_time = convert_timestamp_to_system_time(&span.timestamp); 170 + let timestamp = updated_at.unwrap_or(&span.timestamp); 171 + let start_time = convert_timestamp_to_system_time(timestamp); 171 172 builder.start_time = Some(start_time); 172 173 173 174 if let Some(duration) = convert_duration_ms(span.duration_ms) { ··· 184 185 ); 185 186 } 186 187 187 - fn export_chat(&self, span: &GenAiSpan) { 188 + fn export_chat(&self, span: &GenAiSpan, updated_at: Option<&Timestamp>) { 188 189 let mut attributes = vec![ 189 190 KeyValue::new("gen_ai.conversation.id", span.session_id.clone()), 190 191 KeyValue::new("network.transport", "tcp"), ··· 229 230 builder.span_kind = Some(SpanKind::Client); 230 231 builder.attributes = Some(attributes); 231 232 232 - let start_time = convert_timestamp_to_system_time(&span.timestamp); 233 + let timestamp = updated_at.unwrap_or(&span.timestamp); 234 + let start_time = convert_timestamp_to_system_time(timestamp); 233 235 builder.start_time = Some(start_time); 234 236 235 237 if let Some(duration) = convert_duration_ms(span.duration_ms) { ··· 246 248 ); 247 249 } 248 250 249 - fn export_thinking(&self, span: &GenAiSpan) { 251 + fn export_thinking(&self, span: &GenAiSpan, updated_at: Option<&Timestamp>) { 250 252 let mut attributes = vec![ 251 253 KeyValue::new("gen_ai.conversation.id", span.session_id.clone()), 252 254 KeyValue::new("network.transport", "tcp"), ··· 280 282 builder.span_kind = Some(SpanKind::Internal); 281 283 builder.attributes = Some(attributes); 282 284 283 - let start_time = convert_timestamp_to_system_time(&span.timestamp); 285 + let timestamp = updated_at.unwrap_or(&span.timestamp); 286 + let start_time = convert_timestamp_to_system_time(timestamp); 284 287 builder.start_time = Some(start_time); 285 288 286 289 if let Some(duration) = convert_duration_ms(span.duration_ms) {