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

Type erasure for registry/subscribers #2891

Open
colinmarc opened this issue Feb 23, 2024 · 2 comments
Open

Type erasure for registry/subscribers #2891

colinmarc opened this issue Feb 23, 2024 · 2 comments

Comments

@colinmarc
Copy link

The complex types on tracing-subscriber Subscribers and Layers make them a little bit difficult to work with. Consider the following example, which switches on a command line flag to write a trace log to a directory:

let mut registry = tracing_subscriber::registry().with(printed_log);

if let Some(dir) = bug_report_dir {
    // Additionally write a trace log with everything to the bug report dir.
    let file = std::fs::File::create(dir.as_ref().join("server.log"))?;
    let trace_filter = tracing_subscriber::EnvFilter::new("server=trace");

    let trace_log = tracing_subscriber::fmt::layer()
        // This also hits #1817
        .with_ansi(false)
        .with_writer(Mutex::new(file))
        .with_filter(trace_filter);

    registry = registry.with(trace_log);
 }

This fails to compile with:

error[E0308]: mismatched types
   --> mm-server/src/main.rs:142:20
    |
129 |     let mut registry = tracing_subscriber::registry().with(printed_log);
    |                        ------------------------------------------------ expected due to this value
...
142 |         registry = registry.with(trace_log);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected `tracing_subscriber::Registry`, found `Layered<Filtered<..., ..., ...>, ...>`
    |
    = note: expected struct `Layered<Filtered<tracing_subscriber::fmt::Layer<tracing_subscriber::Registry, DefaultFields, _>, _, tracing_subscriber::Registry>, tracing_subscriber::Registry, tracing_subscriber::Registry>`
               found struct `Layered<Filtered<Layer<Layered<Filtered<Layer<Registry>, EnvFilter, Registry>, Registry>, LogFull, Format, Mutex<File>>, ..., ...>, ...>`
            the full type name has been written to ...

I'm relatively new to rust, so it could be I'm missing something obvious, but it seems like the type system prevents any conditional logic when setting up logging, which I would expect to be the norm for complicated apps. An imperative fn register(&mut self, impl Layer) would probably fix that case, but there's another problem, which is that the type system around Subscribers is fairly illegible at the moment.

Here's an actual screenshot of my terminal from last night when I was looking for workarounds to this problem:

image

I understand that there are complex requirements here, which in turn necessitate lots of API surface. And I don't have any concrete suggestions to make beyond what I mentioned earlier, so I hope this criticism isn't unwelcome. If someone is willing to point me in the right direction, I'm more than happy to contribute some work on this.

@colinmarc
Copy link
Author

I just discovered that Option<Layer> implements Layer, which makes this problem a lot easier. I'm not sure how I missed that in the docs, but maybe one of the fmt examples should demonstrate that?

@xuorig
Copy link

xuorig commented Mar 2, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants