How to use Rusts tracing_distributed - html

I am trying to use the Rust tracing_distributed package, but I am getting strange and unhelpful errors when using it, and I am assuming I am using it wrong, but there is no documentation and there are no examples about how to use it. Here is an example of what I'm trying to do :
let trace = tracing_distributed::register_dist_tracing_root(traceId, remote_parent_span_id));
println!("trace value: {:?}", trace);
// the result of trace is: Err(NoEnabledSpan)
I have tried passing a few things in as the traceID and remote_parent_span_id including:
traceId = remote_parent_span_id = Some(tracing::Span::current())
As well as:
traceId = Some(tracing::Span::current())
remote_parent_span_id = ~someParentRequestIdGeneratedUpstream~
I know that the current span is not disabled from trying:
let span = tracing::Span::current();
if span.is_disabled() {
println!("CURRENT SPAN DISABELED");
}
So this leads me to think that the issue is coming from not having the subscriber set properly. I am trying to set the subscriber in an init function which is called before this function which looks like this:
let subscriber = tracing_subscriber::registry() // provide underlying span data store
.with(
tracing_subscriber::fmt::layer()
.json()
.with_span_events(FmtSpan::ACTIVE)
.event_format(stackdriver::StackDriverEventFormat::default())
.with_filter(tracing_subscriber::filter::dynamic_filter_fn(
move |m, c| filter_layer.enabled(m, c.to_owned()),
)),
);
let _ = tracing::subscriber::set_global_default(subscriber)
.map_err(|_err| eprintln!("Unable to set global default subscriber"));
Would anyone be willing to provide me with an example of how to use this library? Or can anyone see what I'm doing wrong here? I have tried everything I can think of.

tracing-distributed has a test which demonstrates how to create and use TelemetryLayer.
I made a demo based on it. In this demo, NoEnabledSpan may be caused by missing #[instrument], which creates a Span for function foo. Hope this will help you find the actual cause.
Also tracing-honeycomb is a great use case for tracing-distributed, better check it out.
use std::sync::{Arc, Mutex};
use tracing::{Id, info};
use tracing::instrument;
use tracing_distributed::{Event, Span, Telemetry, TelemetryLayer};
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::registry;
#[derive(Default, Debug)]
pub struct BlackholeVisitor;
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub struct TraceId(pub(crate) u128);
type SpanId = tracing::Id;
impl tracing::field::Visit for BlackholeVisitor {
fn record_debug(&mut self, _: &tracing::field::Field, _: &dyn std::fmt::Debug) {}
}
/// Mock telemetry capability
pub struct TestTelemetry {
spans: Arc<Mutex<Vec<Span<BlackholeVisitor, SpanId, TraceId>>>>,
events: Arc<Mutex<Vec<Event<BlackholeVisitor, SpanId, TraceId>>>>,
}
impl TestTelemetry {
pub fn new(
spans: Arc<Mutex<Vec<Span<BlackholeVisitor, SpanId, TraceId>>>>,
events: Arc<Mutex<Vec<Event<BlackholeVisitor, SpanId, TraceId>>>>,
) -> Self {
TestTelemetry { spans, events }
}
}
impl Telemetry for TestTelemetry {
type Visitor = BlackholeVisitor;
type TraceId = TraceId;
type SpanId = SpanId;
fn mk_visitor(&self) -> Self::Visitor {
BlackholeVisitor
}
fn report_span(&self, span: Span<BlackholeVisitor, SpanId, TraceId>) {
// succeed or die. failure is unrecoverable (mutex poisoned)
let mut spans = self.spans.lock().unwrap();
spans.push(span);
}
fn report_event(&self, event: Event<BlackholeVisitor, SpanId, TraceId>) {
// succeed or die. failure is unrecoverable (mutex poisoned)
let mut events = self.events.lock().unwrap();
events.push(event);
}
}
#[instrument]
fn foo() {
let trace = tracing_distributed::register_dist_tracing_root(TraceId(123), Option::<Id>::None);
println!("trace value: {:?}", trace);
info!("test");
}
fn main() {
let spans = Arc::new(Mutex::new(Vec::new()));
let events = Arc::new(Mutex::new(Vec::new()));
let cap = TestTelemetry::new(spans.clone(), events.clone());
let telemetry_layer = TelemetryLayer::new("test_svc_name", cap, |x| x);
let subscriber = registry::Registry::default()
.with(tracing_subscriber::fmt::Layer::default())
.with(telemetry_layer);
// dbg!(&subscriber);
tracing::subscriber::set_global_default(subscriber).expect("setting global default failed");
foo();
dbg!(&spans);
dbg!(&events);
}
crate versions:
tracing = "0.1.32"
tracing-distributed = "0.4.0"
tracing-subscriber = "0.3.10"

Related

Unit testing CSV parsing logic

I'm using the CSV crate to read CSV files. I then parse the content. I would like to unit test the parsing logic. Here's a simplified version of the code:
fn main() -> Result<(), Box<dyn Error>> {
let mut rdr = csv::ReaderBuilder::new()
.from_path("test.csv")?;
process(rdr.records());
Ok(())
}
fn process(iter: StringRecordsIter<File>) -> Result<String, String> {
for result in iter {
// Parsing takes place here
println!("{:?}", result);
}
// Post-parsing using entire file content takes place here
Ok(String::from("My Result Here"))
}
In my unit test I would like to be able to construct sequences of StringRecord objects, pass them to the process() method and validate the results. I can successfully create a StringRecord using the simple StringRecord::new() and fill it with values using record.push_field("my field value"). However, I'm struggling to create an iterator that returns my values to pass to the process(). Any suggestions? I'm happy to change the arguments to process() if this makes things easier.
The suggestion made by Jmb to change the signature of process() to fn process(iter: impl Iterator<Item = csv::Result<StringRecord>>) -> Result<String, String> works nicely.
Here's the solution in detail. Firstly the only change to process() is to make it accept more types:
fn process(iter: impl Iterator<Item = csv::Result<StringRecord>>) -> Result<String, String> {
for result in iter {
// Parsing takes place here
println!("{:?}", result);
}
// Post-parsing using entire file content takes place here
Ok(String::from("My Result Here"))
}
The main() remains identical as rdr.records can still be passed to process(). Then the testing looks like this:
#[test]
fn my_test() -> Result<(), String> {
let record1 = result_record(&["Value 1", "Value 2"]);
let record2 = result_record(&["Value 3", "Value 4"]);
let records = vec![record1, record2];
let result = process(records.into_iter())?;
assert_eq!("My Result Here", result);
Ok(())
}
fn result_record(fields: &[&str]) -> csv::Result<StringRecord> {
let mut record = StringRecord::new();
for field in fields {
record.push_field(field);
}
Ok(record)
}

How do I fix "the method `clone` exists but the following trait bounds were not satisfied" when cloning a struct with generics and a function pointer? [duplicate]

This question already has answers here:
Deriving a trait results in unexpected compiler error, but the manual implementation works
(2 answers)
Closed 2 years ago.
I'm writing a function that will create a menu interface in the terminal. To use the function, it needs to be passed a Vec<menu_option>
#[derive(Clone)]
pub struct menu_option<'a, T> {
pub command: &'a str,
pub description: &'a str,
pub action: menu_option_action<'a, T>,
}
#[derive(Clone)]
pub enum menu_option_action<'a, T> {
sub_menu(Vec<menu_option<'a, T>>),
callback(fn(state: T) -> T),
leave,
}
When I design the menu, it can have multiple levels and there can be repeats of a menu_action. Namely, each layer has a "leave"/"return":
// In my actual code I construct a vector of `menu_option`s
fn example() {
type StateType = i32;
let mut state: StateType = 88;
let leave_option: menu_option<&mut StateType> = menu_option::<&mut StateType> {
command: "l",
description: "leave",
action: menu_option_action::leave,
};
let a = leave_option.clone();
}
error[E0599]: no method named `clone` found for struct `menu_option<'_, &mut i32>` in the current scope
--> src/lib.rs:24:26
|
2 | pub struct menu_option<'a, T> {
| -----------------------------
| |
| method `clone` not found for this
| doesn't satisfy `menu_option<'_, &mut i32>: std::clone::Clone`
...
24 | let a = leave_option.clone();
| ^^^^^ method not found in `menu_option<'_, &mut i32>`
|
= note: the method `clone` exists but the following trait bounds were not satisfied:
`&mut i32: std::clone::Clone`
which is required by `menu_option<'_, &mut i32>: std::clone::Clone`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `clone`, perhaps you need to implement it:
candidate #1: `std::clone::Clone`
How do I fix this?
I tried searching online and couldn't find a solution, at least, not one that worked for me (what I found was old Rust, I think)
I don't know what stops the clone because the only use of the T type is a function pointer which I thought was cloneable.
It works when you implement Clone yourself on menu_option & menu_option_action. By default, since your struct/enum has a type parameter, the macro expansion of the #[derive(Clone)] attribute will restrain the clone implementation for your type to T: Clone.
In your case, not only is this requirement not needed, but it is also very unlikely to be ever respected (e.g. &mut T does not implement Clone). By implementing Clone by hand, you can get rid of the T: Clone requirement and it works!
Note that function pointers implement Copy which is why the menu_option_action::callback(*f) works:
type StateType = i32;
pub struct menu_option<'a, T> {
pub command: &'a str,
pub description: &'a str,
pub action: menu_option_action<'a, T>,
}
impl<'a, T> Clone for menu_option<'a, T> {
fn clone(&self) -> Self {
menu_option {
command: self.command.clone(),
description: self.description.clone(),
action: self.action.clone(),
}
}
}
pub enum menu_option_action<'a, T> {
sub_menu(Vec<menu_option<'a, T>>),
callback(fn(T) -> T),
leave,
}
impl<'a, T> Clone for menu_option_action<'a, T> {
fn clone(&self) -> Self {
match self {
menu_option_action::sub_menu(sub) => menu_option_action::sub_menu(sub.to_vec()),
menu_option_action::callback(f) => menu_option_action::callback(*f),
menu_option_action::leave => menu_option_action::leave,
}
}
}
fn main() {
let mut state: StateType = 88;
let leave_option: menu_option<&mut StateType> = menu_option {
command: "l",
description: "leave",
action: menu_option_action::leave,
};
let a = leave_option.clone();
}

lib for configuration handling in an ergonomic way

I'm writing a common library for loading and handling configuration for my applications,
using the config crate.
Im trying to make it as ergonomic as possible to the user, but can't seem to figure it out.
my lib.rs:
impl RunEnv {
fn to_string(&self) -> String {
match self {
RunEnv::Production => "prod".to_string(),
RunEnv::Dev => "dev".to_string(),
RunEnv::Staging => "stag".to_string(),
}
}
}
impl FromStr for RunEnv {
type Err = String;
fn from_str(s: &str) -> Result<RunEnv, String> {
match s {
"dev" => Ok(RunEnv::Dev),
"stag" => Ok(RunEnv::Staging),
"prod" => Ok(RunEnv::Production),
_ => Err(format!("Could not parse {:?}", s)),
}
}
}
#[derive(Debug, StructOpt)]
#[structopt(name = "CLI Options", about = "Common CLI options for running applications")]
pub struct Arguments {
/// Run in a specific environment mode: dev, stag, prod.
// short and long flags (-e, --env) will be deduced from the field's name
#[structopt(short, long, default_value = "dev")]
pub env: RunEnv,
}
pub trait LoadConfig {
fn new() -> Result<Config, ConfigError>{
const PACKAGE_NAME: &'static str = env!("CARGO_PKG_NAME");
let mut s = Config::new();
let args = Arguments::from_args();
let mut conf_path = String::new();
match args.env {
RunEnv::Production => {
conf_path = format!("/path/to/config/{}/config.toml", PACKAGE_NAME);
}
RunEnv::Staging => {
conf_path = format!("/path/to/config/{}/config.toml", PACKAGE_NAME);
}
RunEnv::Dev => {
conf_path = "tests/config.toml".to_string();
}
}
// Start off by merging in the "default" configuration file
s.merge(File::with_name(&conf_path))?;
// Add in the current environment
// Default to 'dev' env
s.set("run_mode", args.env.to_string())?;
Ok(s)
}
}
In my app:
setting.rs
#[derive(Debug, Deserialize)]
pub struct Server {
port: u32,
address: String,
}
#[derive(Debug, Deserialize)]
pub struct Settings {
server: Server,
run_mode: Option<String>,
}
impl LoadConfig for Settings {}
main.rs
fn main() {
let conf: Settings = Settings::new().unwrap().try_into().unwrap();
println!("{:?}", conf);
And here is my problem, I'm trying to "hide" the.unwrap().try_into().unwrap(); part away
so the lib user will only need to define his setting.rs and run let conf: Settings = Settings::new()
If i move .try_into() inside a trait then I'm getting an error i can't find a way to go around:
| s.try_into()
| ^^^^^^^^ the trait `_IMPL_DESERIALIZE_FOR_Configuration::_serde::Deserialize<'_>` is not implemented for `config::config::Config`
I'm new to rust and probably missing some obvious things
For convention the new function is the way to build an instance and must be an inherent method of the struct,
a method available directly on a type.
In your example you are trying to define new as a trait default method.
If it was at all possible the signature should be:
pub trait LoadConfig {
fn new() -> Self {
}
}
Such trait method is impossible to implement because the trait does not know nothing about Self concrete type.
To follow this convention it is best to rename the LoadConfig::new trait method to something else:
pub trait LoadConfig {
fn load() -> Result<Config, ConfigError>;
}
Then implement the new constructor function as an inherent method, for example:
impl Settings {
fn new() -> Settings {
let config = Settings::load().unwrap(); // TBD: manage errors
let port: u32 = config.get("port").unwrap_or("8080").parse().unwrap();
Settings {
server: Server {
port: port,
address: config.get("address").unwrap_or("localhost").to_owned()
},
run_mode: None
}
}
}
Note that a robust implementation should not unwrap but manage more explicitly config errors.

Function refered from the stored in struct does not give the ownership up

I'm writing a algorithm testbench to compare performance in Rust.
I want to store a bunch of function for an algorithm in a struct, and apply those functions to some data.
When I call the function by reference, which stored in the struct, I couldn't figure out the lifetime.
struct Alg<'a, 'b, 'c> {
alg1: &'c Fn(&'a A<'a>, &'b B<'b>) -> usize,
alg2: &'c Fn(&'a A<'a>, &'b B<'b>) -> String,
}
struct A<'a> {
a_str: &'a str,
}
struct B<'b> {
b_str: &'b str,
}
fn concat<'a, 'b>(_a: &'a A<'a>, _b: &'b B<'b>) -> String {
_a.a_str.to_string() + &_b.b_str.to_string()
}
fn length<'a, 'b>(_a: &'a A<'a>, _b: &'b B<'b>) -> usize {
_a.a_str.len() + _b.b_str.len()
}
fn run1<'a, 'b, 'c>(_a: &'a A<'a>, _b: &'b B<'b>, _f_c: &'c Alg<'a, 'b, 'c>) {
println!("{}", &(_f_c.alg1)(_a, _b));
}
fn run2<'a, 'b, 'c>(_a: &'a A<'a>, _b: &'b B<'b>, _f_c: &'c Alg<'a, 'b, 'c>) {
println!("{}", &(_f_c.alg2)(_a, _b));
}
fn main() {
let f_struct = Alg {
alg1: &length,
alg2: &concat,
};
for _i in 0..2 {
let a_str = "ABC";
let a = A { a_str: a_str };
for _j in 0..2 {
let b_str = "BCD";
let b = B { b_str: b_str };
println!("{}", concat(&a, &b)); // This works
println!("{}", (f_struct.alg1)(&a, &b)); // I expect that `concat` or `length` in `f_struct` may finished borrowing `a` or `b' here, as like as `println!("{}",concat(&a,&b))`
//run1(&a,&b,&f_struct);
//run2(&a,&b,&f_struct);
}
}
}
When I run this, I get an error message like:
error[E0597]: `a` does not live long enough
--> src/main.rs:43:44
|
43 | println!("{}", (f_struct.alg1)(&a, &b)); // I expect that `concat` or `length` in `f_struct` may finished borrowing `a` or `b' here, as like as `println!("{}",concat(&a,&b))`
| --------------- ^^ borrowed value does not live long enough
| |
| borrow used here, in later iteration of loop
...
47 | }
| - `a` dropped here while still borrowed
error[E0597]: `b` does not live long enough
--> src/main.rs:43:48
|
43 | println!("{}", (f_struct.alg1)(&a, &b)); // I expect that `concat` or `length` in `f_struct` may finished borrowing `a` or `b' here, as like as `println!("{}",concat(&a,&b))`
| --------------- ^^ borrowed value does not live long enough
| |
| borrow used here, in later iteration of loop
...
46 | }
| - `b` dropped here while still borrowed
What is the difference between println!("{}",concat(&a,&b)) and println!("{}",(f_struct.alg1)(&a,&b))?
I thought that I have to indicate something that the function no more borrows the value with lifetime 'a or 'b, but I couldn't find it from rust-by-example or rust-book.
I've tried to apply coercion like 'c: 'a + 'b, but this seems not to help.
These questions are related, but not so clear to me.
Rust lifetime error
Rust lifetime error expected concrete lifetime but found bound lifetime
Questions about Rust lifetime
Point
I want to store functions in the struct
I could try another way like not to store functions in the struct
But I want to understand the reason when this approach is impossible
Quick solution
You have too many lifetime specifiers. Remove the lifetimes for references in your function parameters. Eg. replace alg1: &'c Fn(&'a A<'a>, &'b B<'b>) -> usize with alg1: &'c Fn(&A<'a>, &B<'b>) -> usize (and similar changes to all functions (playground).
Explanation
First, let's simplify your code a bit and rename some of the lifetimes so that we know which one we are talking about:
struct Alg<'Alg_a, 'Alg_b> {
alg1: &'Alg_b Fn(&'Alg_a A<'Alg_a>) -> usize,
}
struct A<'A_a> {
a_str: &'A_a str,
}
fn length<'L_a>(a: &'L_a A<'L_a>) -> usize {
a.a_str.len()
}
fn main() {
let f_struct = Alg {
alg1: &length,
};
for _i in 0..2 {
let a_str = "ABC";
let a = A { a_str: a_str };
println!("{}", length (&a)); // This works
println!("{}", (f_struct.alg1) (&a)); // This doesn't
}
}
You can check on the playground that this exhibits the same error as your code.
When you call (f_struct.alg1)(&a), the compiler tries to find good values for the lifetimes 'Alg_a and 'Alg_b associated with f_struct. Since f_struct is defined outside the loop, then those lifetimes must be the same for all iterations of the loop. However Alg::alg1 is defined as Fn(&'Alg_a …) which means that 'Alg_a must be the lifetime of the parameter a which is only valid for a single loop iteration. Hence the error.
By not specifying the lifetime of the parameter, I allow the compiler to choose different lifetimes for the parameter a and for 'Alg_a, and in particular to choose a different lifetime for the parameter each time the function is called. So the lifetime for the parameter can be limited to a single loop iteration while 'Alg_a may be longer:
struct Alg<'Alg_a, 'Alg_b> {
alg1: &'Alg_b Fn(&A<'Alg_a>) -> usize,
}
struct A<'A_a> {
a_str: &'A_a str,
}
fn length<'L_a>(a: &A<'L_a>) -> usize {
a.a_str.len()
}
fn main() {
let f_struct = Alg {
alg1: &length,
};
for _i in 0..2 {
let a_str = "ABC";
let a = A { a_str: a_str };
println!("{}", length (&a)); // This works
println!("{}", (f_struct.alg1) (&a)); // Now this does too
}
}
playground
Why does calling length directly work?
When calling length directly, the compiler only needs to determine the lifetime 'L_a and there is nothing that requires this lifetime to last for more than a single loop iteration, so there is no conflict.
Note
As noted by #VikramFugro, this only work because a_str = "ABC" creates a slice with a 'static lifetime which can be shrunk down to 'Alg_a or 'L_a as required. Using a dynamic string (let a_str = String::from("ABC")) does not work. We need to declare alg1 as &'Alg_b for<'F_a> Fn(&A<'F_a>) -> usize instead of using the 'Alg_a lifetime on the Alg struct:
struct Alg<'Alg_b> {
alg1: &'Alg_b for<'F_a> Fn(&A<'F_a>) -> usize,
}
playground
Additionally, Rust 2018 allows us to use an anonymous lifetime '_ instead of the for<'a> … syntax, for example &'Alg_b Fn(&A<'_>) -> usize (playground).

Is there a way to reference the constructor of a type?

In Swift you can reference a function, assign it a value, then use it later. We all know that. But I wonder if we can do that with initializers. Here is some example code. Suppose I have a User struct:
struct User {
let name: String
let age: UInt
init(name: String) {
self.name = name
age = 0
}
}
And I have an array of names
let names = ["Cooper", "Murph", "Brand", "Dr. Mann"]
And I want to map those names to User instances. I can do it like this:
let users = map(names, { User(name: $0) })
Although this seems good I feel using the closure that map function takes is unnecessary. I mean it basically takes a name and produces User. But we defined that in constructor of User struct. Why we need to repeat it? Is there a way to get constructor as function and pass it directly to the map function?
Short answer: no, you can’t reference init as a stand-alone function. It’d be nice though.
You can access member functions like this:
extension User {
func getName() -> String { return name }
}
// will be a function that takes a User object,
// and returns a new function that is getName
// called on that object:
let f = User.getName
let u = User("Fred")
// g will be a function that calls getName on u
let g = f(u)
g() // returns "Fred"
If User were a class not a struct, you could also do this:
// h will be equivalent to g above...
let h = u.getName
h() // returns "Fred"
Calling init feels like it ought to be more like the latter, since it creates fresh objects rather than taking existing objects. User.init ought to return a function that takes a name and returns a User (though you have two initializers so you’d need to provide some type context). But Swift won’t let you do that (tells you “Initializer cannot be referenced without arguments”).
One interesting thing though is protocols can require certain kinds of initializers, so you can do the following (fairly silly) thing to fake a function that initializes any type, provided for amusement only rather than practical use:
protocol StringInitializable {
init(_ s: String)
}
// no implementation needed as User already conforms
extension User: StringInitializable { }
func initerFromString<T: StringInitializable>(s: String) -> T {
return T(s)
}
let users: [User] = map(names, initerFromString)
The above fixes the type using the type of the users array, but you could do it by fixing the type of the function instead:
let userInit: String->User = initerFromString
let moreUsers = map(names, userInit)
struct Monster: StringInitializable {
let name: String
init(_ name: String) { self.name = name }
}
let monsterInit: String->Monster = initerFromString
let monsters = map(names, monsterInit)
(Somewhere this is actually used to actual practical effect is in ExtensibleCollectionType)
If you just want to avoid repetition, you can skip giving named parameters by putting an underscore _ in front of the parameter.
struct User {
let name: String
let age: UInt
init(_ name: String) {
self.name = name
age = 0
}
init(_ name: String, _ age : UInt) {
self.name = name
self.age = age
}
}
let names = ["Cooper", "Murph", "Brand", "Dr. Mann"]
let users = map(names, {User($0)})