Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dora record #365

Merged
merged 9 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ jobs:
cargo publish -p dora-runtime --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
cargo publish -p dora-daemon --token ${{ secrets.CARGO_REGISTRY_TOKEN }}

# Publish extension crates
cargo publish -p dora-record --token ${{ secrets.CARGO_REGISTRY_TOKEN }}



windows-release:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
# These are backup files generated by rustfmt
**/*.rs.bk

# Remove arrow file from dora-record
**/*.arrow

# Removing images.
*.jpg
*.png
Expand Down
17 changes: 10 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ members = [
"libraries/shared-memory-server",
"libraries/extensions/download",
"libraries/extensions/telemetry/*",
"libraries/extensions/zenoh-logger",
"libraries/extensions/dora-record",
"libraries/extensions/ros2-bridge",
"libraries/extensions/ros2-bridge/msg-gen",
"libraries/extensions/ros2-bridge/msg-gen-macro",
Expand Down
7 changes: 7 additions & 0 deletions examples/python-operator-dataflow/dataflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,10 @@ nodes:
inputs:
image: webcam/image
bbox: object_detection/bbox
- id: dora-record
custom:
build: cargo build -p dora-record
source: ../../target/release/dora-record
haixuanTao marked this conversation as resolved.
Show resolved Hide resolved
inputs:
image: webcam/image
bbox: object_detection/bbox
8 changes: 8 additions & 0 deletions examples/rust-dataflow/dataflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,11 @@ nodes:
source: ../../target/debug/rust-dataflow-example-sink
inputs:
message: runtime-node/rust-operator/status
- id: dora-record
custom:
build: cargo build -p dora-record
source: ../../target/debug/dora-record
inputs:
message: runtime-node/rust-operator/status
tick: dora/timer/millis/100
random: rust-node/random
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "zenoh-logger"
name = "dora-record"
version.workspace = true
edition = "2021"
documentation.workspace = true
Expand All @@ -9,4 +9,7 @@ license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
zenoh = "0.7.0-rc"
dora-node-api = { workspace = true, features = ["tracing"] }
eyre = "0.6.8"
chrono = "0.4.31"
dora-tracing = { workspace = true }
134 changes: 134 additions & 0 deletions libraries/extensions/dora-record/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use chrono::{DateTime, Utc};
use dora_node_api::{
self,
arrow::{
array::{make_array, Array, Int64Array, ListArray, StringArray},
buffer::{OffsetBuffer, ScalarBuffer},
datatypes::{DataType, Field, Schema},
ipc::writer::FileWriter,
record_batch::RecordBatch,
},
DoraNode, Event, Metadata,
};
use dora_tracing::telemetry::deserialize_to_hashmap;
use eyre::{Context, ContextCompat};
use std::{collections::HashMap, fs::File, sync::Arc};

// Remove once arrow-rs 48.0 is published with access to writer schema.
// See: https://github.com/apache/arrow-rs/pull/4940
struct WriterContext {
writer: FileWriter<File>,
schema: Arc<Schema>,
}
haixuanTao marked this conversation as resolved.
Show resolved Hide resolved

fn main() -> eyre::Result<()> {
let (_node, mut events) = DoraNode::init_from_env()?;

let mut writers = HashMap::new();
while let Some(event) = events.recv() {
match event {
Event::Input { id, data, metadata } => {
match writers.get_mut(&id) {
None => {
let field_timestamp = Field::new("timestamp", DataType::Int64, true);
let field_trace_id = Field::new("trace_id", DataType::Utf8, true);
let field_span_id = Field::new("span_id", DataType::Utf8, true);
let field_values =
Arc::new(Field::new("item", data.data_type().clone(), true));
let field_data = Field::new(id.clone(), DataType::List(field_values), true);

let schema = Arc::new(Schema::new(vec![
field_trace_id,
field_span_id,
field_timestamp,
field_data,
]));
let file = std::fs::File::create(format!("{id}.arrow")).unwrap();

let writer = FileWriter::try_new(file, &schema).unwrap();
let mut writer_context = WriterContext { writer, schema };
write_event(&mut writer_context, data.into(), &metadata)
.context("could not write first record data")?;
writers.insert(id.clone(), writer_context);
}
Some(writer_context) => {
write_event(writer_context, data.into(), &metadata)
.context("could not write first record data")?;
haixuanTao marked this conversation as resolved.
Show resolved Hide resolved
}
};
}
Event::InputClosed { id } => match writers.remove(&id) {
None => {}
Some(mut writer) => writer
.writer
.finish()
.context("Could not finish arrow file")?,
},
_ => {}
}
}

let result: eyre::Result<Vec<_>> = writers
.iter_mut()
.map(|(_, wc)| -> eyre::Result<()> {
wc.writer
.finish()
.context("Could not finish writing arrow file")?;
Ok(())
})
.collect();
result.context("One of the input recorder file writer failed to finish")?;
haixuanTao marked this conversation as resolved.
Show resolved Hide resolved

Ok(())
}

/// Write a row of data into the writer
fn write_event(
writer_context: &mut WriterContext,
data: Arc<dyn Array>,
metadata: &Metadata,
) -> eyre::Result<()> {
let offsets = OffsetBuffer::new(ScalarBuffer::from(vec![0, data.len() as i32]));
let field = Arc::new(Field::new("item", data.data_type().clone(), true));
let list = ListArray::new(field.clone(), offsets, data.clone(), None);

let timestamp = metadata.timestamp();
let timestamp = timestamp.get_time().to_system_time();

let dt: DateTime<Utc> = timestamp.into();
let timestamp_array = Int64Array::from(vec![dt.timestamp_millis()]);
let timestamp_array = make_array(timestamp_array.into());

let string_otel_context = metadata.parameters.open_telemetry_context.to_string();
let otel_context = deserialize_to_hashmap(&string_otel_context);
let traceparent = otel_context.get("traceparent").clone();
let trace_id = match traceparent {
None => "",
Some(trace) => trace.split("-").nth(1).context("Trace is malformatted")?,
};
let span_id = match traceparent {
None => "",
Some(trace) => trace.split("-").nth(2).context("Trace is malformatted")?,
};
let trace_id_array = StringArray::from(vec![trace_id]);
let trace_id_array = make_array(trace_id_array.into());
let span_id_array = StringArray::from(vec![span_id]);
let span_id_array = make_array(span_id_array.into());

let record = RecordBatch::try_new(
writer_context.schema.clone(),
vec![
trace_id_array,
span_id_array,
timestamp_array,
make_array(list.into()),
],
)
.context("Could not create record batch with the given data")?;
writer_context
.writer
.write(&record)
.context("Could not write recordbatch to file")?;

Ok(())
}
11 changes: 8 additions & 3 deletions libraries/extensions/telemetry/tracing/src/telemetry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,17 @@ pub fn serialize_context(context: &Context) -> String {
}

pub fn deserialize_context(string_context: &str) -> Context {
let mut map = MetadataMap(HashMap::new());
let map = MetadataMap(deserialize_to_hashmap(string_context));
global::get_text_map_propagator(|prop| prop.extract(&map))
}

pub fn deserialize_to_hashmap(string_context: &str) -> HashMap<&str, &str> {
let mut map = HashMap::new();
for s in string_context.split(';') {
let mut values = s.split(':');
let key = values.next().unwrap();
let value = values.next().unwrap_or("");
map.0.insert(key, value);
map.insert(key, value);
}
global::get_text_map_propagator(|prop| prop.extract(&map))
map
}
15 changes: 0 additions & 15 deletions libraries/extensions/zenoh-logger/src/main.rs

This file was deleted.

Loading