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

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

Open
str4d opened this issue Jul 7, 2020 · 5 comments
Open

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

str4d opened this issue Jul 7, 2020 · 5 comments
Labels
crate/core Related to the `tracing-core` crate kind/feature New feature or request

Comments

@str4d
Copy link

str4d commented Jul 7, 2020

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

  • Use TryInto from the slice to a fixed-size array.
    • I think this requires FFI-compatible const generics.
  • Have 32 separate FFI methods for each concrete array size
    • This is more awkward to work with, but maybe not too much more complex to implement in e.g. C preprocessor macros over the generic version (I haven't implemented that part yet).
    • Don't need a zero-size method as there is always at least one filled field - message.
  • Use a [T; 32] inside the FFI method, and fill in unused positions with (placeholder_field, None).
    • This requires having fields that are never used in real logging, which could maybe be implemented by instantiating a 32-field callsite inside the FFI method and then never using it for any real event.
@hawkw
Copy link
Member

hawkw commented Jul 7, 2020

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:

values: &'a [(&'a Field, Option<&'a (dyn Value + 'a)>)],

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?

@hawkw hawkw added crate/core Related to the `tracing-core` crate kind/feature New feature or request labels Jul 7, 2020
@str4d
Copy link
Author

str4d commented Jul 12, 2020

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
Copy link

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
Copy link
Contributor

nagisa commented Aug 18, 2021

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
Copy link

BrynCooke commented Oct 25, 2023

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 on ValueSet lengths 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
crate/core Related to the `tracing-core` crate kind/feature New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants