tokio-rs / tracing

Application level tracing for Rust.
https://tracing.rs
MIT License
5.54k stars 727 forks source link

Pass slices into FieldSet::value_set instead of array references #782

Open str4d opened 4 years ago

str4d commented 4 years ago

Feature Request

Motivation

I'm trying to write FFI wrapper methods around tracing, and the simplest API is to pass a slice of values across as (values: *const *const c_char, len: usize). However, FieldSet::value_set takes a reference to a fixed-size array, and it isn't possible to generically construct a ValueSet (or have more than 32 fields when not using the macro).

Proposal

Change:

pub fn value_set<'v, V>(&'v self, values: &'v V) -> ValueSet<'v> where V: ValidLen<'v>

to

pub fn value_set<'v, V>(&'v self, values: &'v V) -> ValueSet<'v> where V: Borrow<[(&'a Field, Option<&'a (dyn Value + 'a)>)]>

(or the correct variant of this, as defined by people who actually know how this is used by the rest of the tracing internals 😄).

Alternatives

hawkw commented 4 years ago

The reason this method takes arrays rather than slices is in order to validate that their lengths are less than 32 elements statically. This is used to emit an error from the macros at compile time when too many fields are passed.

However, the fields are stored as a slice internally: https://github.com/tokio-rs/tracing/blob/c4a6a6dccb426aeb677e7e64877a8007666a1f3f/tracing-core/src/field.rs#L85

We could consider adding a separate constructor that takes a slice and validates the length at runtime (either with an assertion or by making the method fallible). This could be used in cases like FFI. We wouldn't want to change the existing method, as the macros would no longer be able to check lengths statically, but it would be fine to add a new one for this use case.

What do you think?

str4d commented 4 years ago

I'd be happy with a separate slice-compatible constructor. It would also be useful to document how to construct a compatible slice; Boxing is one option (and likely the direction I'll be going in to be able to handle arbitrary values across FFI), but hints on how else to satisfy the slice constraints (that don't require delving into how the valueset! macro is implemented) would be handy.

mjte-riot commented 3 years ago

For what it's worth, I would also be very interested in this being solved in 0.2, which I see is part of #922. We have an FFI API that exposes event and span calls into tracing. Even after getting dynamic fields working, the 32-field limitation is the next step.

From reading the comments for ValidLen, it looks as though the reason for it is just an optimization based on the static allocation restriction, and '32" is likely arbitrary? Any idea if there is a deeper reasoning behind the 32-field limit? At the other end of our log/event pipeline would be a sink for sending data to our metrics systems, which can handle hundreds of fields in a given event.

nagisa commented 3 years ago

The reason this method takes arrays rather than slices is in order to validate that their lengths are less than 32 elements statically. This is used to emit an error from the macros at compile time when too many fields are passed.

What is the reason for the 32-field limit?

BrynCooke commented 1 year ago

As length validation has been removed in #2508 would that make a difference to allowing slices in 1.x? The ValidLen trait is documented as:

/// Restrictions onValueSetlengths were removed in #2508 but this type remains for backwards compatibility.

Maybe ValidLen can be implemented for all slices instead of just arrays with fixed size.